Cannot update the nested Array of the boolean - javascript

I am trying to update an array to show the router is up by using a true or false statement.
But I am getting a response back that "record is updated" but I am not able to see the change in MongoDB collection.
This is my function I am running
exports = async function({ body }) {
const data = JSON.parse(body.text());
const ACAS_Mission = data.ACAS_Mission;
const terminal = data.terminals[0].terminal;
const router = data.terminals[0].XLESS.router;
const comstat = context.services
.get("mongodb-atlas")
.db("Comstat")
.collection("comstat");
// Find the document
const filter = { ACAS_Mission, "terminals.terminal": terminal };
const document = await comstat.findOne(filter);
console.log("Document:", JSON.stringify(document));
// Update the document
const updateFilter = { ACAS_Mission, "terminals.terminal": terminal };
const update = { $set: { "terminals.$[t].XLESS.router": router } };
const options = { arrayFilters: [{ "t.terminal": terminal }] };
const result = await comstat.updateOne(updateFilter, update, options);
console.log("Update result:", JSON.stringify(result));
return { message: "Record updated." };
};
and this is the document I am trying to update
MongoDB Document
The JSON Body that I am passing when I do a PUT
{
"ACAS_Mission": "xx53583",
"terminals": [
{
"terminal": "SNN573330",
"XLESS": {
"router": true
}
}
]
}

As you wrote in your comment, MongoDB processes the request, but there are no changes. That means that nothing in your datebase matched your query (as one may conclude from matchedCount being 0).
Check your query: Your screenshot shows that terminals contains an array containing another array containing an object. You are searching for an array directly containing an object, so adding [braces] around the statement might work.

Was able to change the JSON body and a few function fixes and it works!
{
"ACAS_Mission": "xx53583",
"terminals": [
[
{
"terminal": "SNN573330",
"NodeID": 251,
"XLESS": {
"router": false
}
}
]
]

Related

How to parse json if Key'name dynamicly changes each time node js

I receive JSON data from the service, but the keys change in the data with each request, below I will give an example in three versions.
Exmaple 1:
{
"trackingPayloads": {
"Rltyn4gLRIWRKj9kS0YpWXytG81GZwcPWjEE7f31ALlq": "{"title":"Red Shoes","index":3,"id":"17777","type":"category"}',
"ywtA6OyM0hzVZZvnUjxoxJDI1Er9ArfNr8XKyi1D5Zzk": "{"title":"White Shoes","index":3,"id":"17777","type":"category"}',
}
}
Example 2:
{
"trackingPayloads": {
"36tW7DqZ3H9KKBEAumZmowmUwmDRmVCjQgv5zi9GM3Kz": "{"title":"Red Shoes","index":3,"id":"17777","type":"category"}',
"OgtE51n3YtvrVXWLFjPmpnRt2k5DExF7ovxmBTZrZ6wV": "{"title":"White Shoes","index":3,"id":"17777","type":"category"}',
}
}
Example 3:
{
"trackingPayloads": {
"k2toY29glt2JEp9Wi1X5M7ocno0E0mS4JQVyDuGyQ2rM": "{"title":"Red Shoes","index":3,"id":"17777","type":"category"}'",
"5ef2ec3c3573eebecc9690b69619ec7b9c93b609": "{"title":"White Shoes","index":3,"id":"17777","type":"category"}',
}
}
As you can see, the data included in the keys does not change since I am requesting the same information, but the key will change with each request.
Please help, what are the options to get the data Title, Index and any other content in these keys using node js?
Only one option came to my mind - to rename the keys upon receipt in 1,2,3 ... and then get data from them, but this needs to be done dynamically, since about 120 requests per minute are made, you need to get this data quickly, there are no options to save it to a file (I didn’t understand how)
UPDATE, added my code.
I am attaching an example of my code, the idea is to eventually get the data I need from the right keys from trackingPayloads, please help with the code <3
const AwaitAPIResponse = await ProductAPI(product_sku);
const $ = cheerio.load(AwaitAPIResponse);
const JSONDATA = [];
$('pre').each(function() {
JSONDATA.push($(this).text());
});
const ProductJson = JSON.parse(JSONDATA[0]) // this is where I get all the data
const MainJson = ProductJson["trackingPayloads"] // here I go to the trackingPayloads you saw above
How can I get the data I need?
You can use Object.keys() to get all the different keys of an object and use a loop to go through them.
Therefore, you can rework this code in such a way that each of the values is stored as an element in an array, maybe makes the data easier to work with:
const convert = object => {
const ret = []
for (const key of Object.keys(object)) {
ret.push(object[key])
}
return ret
}
This will give you following result for your use case:
[{"title":"Red Shoes","index":3,"id":"17777","type":"category"},
{"title":"Red Shoes","index":3,"id":"17777","type":"category"}]
The way you'd call this is as follows:
const some_parsed_json = {
"k2toY29glt2JEp9Wi1X5M7ocno0E0mS4JQVyDuGyQ2rM": {
title:"Red Shoes",
index:3,
id:"17777",
type:"category"
},
"5ef2ec3c3573eebecc9690b69619ec7b9c93b609": {
title:"Red Shoes",
index:3,
id:"17777",
type:"category"
}
}
const json_object_values = convertor(some_parsed_json)
If you don't car about the key you could use Object.values on the received object to get the values
Object.values(payload)
// With your example it will return:
// [{"title":"Red Shoes","index":3,"id":"17777","type":"category"},
// {"title":"Red Shoes","index":3,"id":"17777","type":"category"}]
or in a more complete example
async function getParsedValues() {
const responseString = await service.getData(); // '{"trackingPayloads":{"Rltyn4gLRIWRKj9kS0YpWXytG81GZwcPWjEE7f31ALlq":{"title":"Red Shoes","index":3,"id":"17777","type":"category"},"ywtA6OyM0hzVZZvnUjxoxJDI1Er9ArfNr8XKyi1D5Zzk":{"title":"White Shoes","index":3,"id":"17777","type":"category"}}}'
const parsedResponse = JSON.parse(responseString); // { trackingPayloads: { Rltyn4gLRIWRKj9kS0YpWXytG81GZwcPWjEE7f31ALlq: { title:'RedShoes', index: 3, id: '17777', type: 'category' }, ywtA6OyM0hzVZZvnUjxoxJDI1Er9ArfNr8XKyi1D5Zzk:{title:'WhiteShoes', index: 3, id: '17777', type: 'category' } }}
const values = Object.values(parsedResponse); // [{"title":"Red Shoes","index":3,"id":"17777","type":"category"}, {title:'WhiteShoes', index: 3, id: '17777', type: 'category' }]
return values;
}

UpdateMany isn't updating the data

In user schema, Location is an array of objects with locations._id is ObjectId.
This is my user service file.
const updatedBy = {
_id: mongoose.Types.ObjectId(req.params.id),
"locations._id": { $in: req.body.locationIds },
};
const updatingData = { $set: { "locations.$.status": req.query.status }};
const user = await userDbServices.updateRecords(updatedBy, updatingData);
In req.body.locationIds, I'm passing an array.
And this one is the user DB service file
exports.updateRecords = async function (updateParam, updatingData) {
return userModel.updateMany(updateParam, updatingData);
};
When I hit the API, The first embedded document of location is updated. But the other ones aren't. How can I solve this?
This is actually the expected behavior of the $ identifier, from the docs:
the positional $ operator acts as a placeholder for the first element that matches the query document
To update multiple elements you want to be using the $[] identifier with arrayFilters, like so:
userModel.updateMany({
_id: mongoose.Types.ObjectId(req.params.id),
"locations._id": { $in: req.body.locationIds },
},
{
$set: {
"locations.$[elem].status": req.query.status
}
},
{
arrayFilters: [
{
"elem._id": {
$in: req.body.locationIds
}
}
]
})
Mongo Playground

mutate in useSWR hook not updating the DOM

It's a next.js app and I populate the data using a useSWR hook.
const { data, error } = useSWR('/api/digest', fetcher, {
revalidateOnFocus: false,
})
The issue is that the DOM doesn't get updated as expected after the mutate() line below. But if I hard code the data as updatedData and pass it as the arg for the mutate it works normally. The fact is that data and the updatedData are the same. See comments below.
Edit: If I click on any Navbar <Link/> it gets updated.
Any clues of what is happening?
const handleAddRowClick = async () => {
const newRow = { category: selectedCategory, entity: selectedEntity }
data.subscription[selectedCategory].push(selectedEntity);
console.log(data); // This data is equal to updatedData
const updatedData = {
"subscription": {
"materialFact": [
"Boeing"
],
"headlines": [
"thejournal",
"onemagazine" // ***This is the value added.
]
}
}
// mutate('/api/digest', data, false) // This does not works.
mutate('/api/digest', updatedData , false) // It works.
}
I am assuming that the data property you use in handleAddRowClick is the same that you get from useSWR. Now, if you update some deeply nested object in data, it doesn't change the data reference. It still points to the old object. So, if you pass it again to mutate, for mutate, the object is still the same and hence, it won't trigger a re-render.
I would recommend that you do something like the following to derive updatedData from data and then pass it to the mutate function.
const handleAddRowClick = async () => {
const updatedData = {
...data,
subscription: {
...data.subscription,
[selectedCategory]: [
...data.subscription[selectedCategory],
selectedEntity,
]
}
}
mutate('/api/digest', updatedData , false);
}
On a side note, you can also use something like immer to simplify copying the state.

load json if exists and append data instead of recreating and overriding the json file

i am working on a function createOrLoadJSON() which should check the application for a existing json file. IF the file not exists, he shall create the file "userData.json" and add data into it.
This whole process should be dynamical, means if i add more objData the following data should append to the json obj instead of recreating the "userData.json" again and overriding the first item after a reload.
the code looks like this:
import userDataJson from './../data/userData.json';
export const userDataControllerMixin = {
data() {
return {
users: [],
userDataAbsPath: 'src/data/userData.json',
};
},
mounted() {
this.getUsers();
},
methods: {
getUsers() {
return userDataJson;
},
User(user, salary) {
this[user] = {
salary: [Number(salary)],
};
// TODO: ADD THESE INTO A PROTOTYPE IN A OTHER MIXIN
// income: [income],
// expenses: [expenses],
},
// GET INPUT FROM USERS DIALOGBOX
getInput(inputName, inputSalary) {
const userName = this.inputName;
const userSalary = this.inputSalary;
const user = new this.User(userName, userSalary);
this.users.push(user);
this.createOrLoadJSON(this.users);
},
// CREATES A JSON WITH DATA FROM THE USERS
createOrLoadJSON(data) {
const fs = require('fs');
const json = JSON.stringify(data, null, '\t');
// TODO: if JSON exists skip creating part and load the existing json file here
if (fs.existsSync(this.userDataAbsPath)) {
console.log('file exists, dont create file, use the existing one and append data');
// LOGIC FOR NOT CREATE THE JSON AGAIN, INSTEAD USE THE EXISTING FILE AS INITIAL AND ALLOW TO APPEND DATA
// read file and add next entry
// ADD new entry instead of override the first one
} else {
console.log('file not exists, so create file');
fs.writeFile(this.userDataAbsPath, json, (error) => {
if (error !== null) {
console.log(error);
}
});
}
this.postUsers();
},
// OUTPRINTS DATA FROM userObj.json
postUsers() {},
},
};
How can i do this? I have absolutely no idea.
Synchronously, you can append to files using fs.appendFileSync
const fs = require('fs');
fs.appendFileSync(filename, json);

How to fix "TypeError: Cannot read property 'node' of undefined" when creating pages programmatically in gatsbyjs

I am trying to create a blog using gatsbyjs, and would like for my blog pages to be created programmatically instead of explicitly creating them in the /src/pages folder.
I am currently trying to query the data from contentful, which I managed to do successfully according to GraphiQL. I followed the steps presented in the documentation for the most part, but I keep on encountering this error whenever my program steps into the ".forEach" function.
exports.createPages=({graphql,actions})=>{
const {createPage}=actions
const blogPost= path.resolve('./src/components/blogComponents/blog-post.js')
return new Promise((resolve,reject)=>{
graphql(`
{
allContentfulBlog{
edges{
node{
slug
}
}
}
}
`).then(results=>{
// console.log(results)
if(results.error){
reject(results.error)
}
// create blog post pages
const posts=results.data.allContentfulBlog.edges
console.log(post)
posts.forEach((post,index)=>{
console.log(`showing slugs: ${posts.node.slug}`)
const previous= index === posts.length-1?null: post[index+1].node
const next= index === 0?null: posts[index-1].node
createPage({
path:post.node.slug,
component:blogPost ,
context:{
slug:post.node.slug,
previous,
next
}
})
})
}).then(resolve)
})
This is the schema of the returned result
"data": {
"allContentfulBlog": {
"edges": [
{
"node": {
"slug": "web-developer-roadmap"
}
},
{
"node": {
"slug": "web-fundamentals-1"
}
}
]
}
}
I expected the "forEach" function to loop through all my blogs and assign the appropriate values the "createPage" function, but instead, it keeps on showing telling me that property of node available in my query is not defined even though I confirmed its presence by logging it to the console as can be seen in the "forEach" function.
The problem with your code it that you are trying to access object like an array
const previous= index === post.length-1?null: post[index+1].node
const next= index === 0?null: post[index-1].node
In the above code, post is single object. i:e { node: {} } and you are accessing it like an array post[index+1].node.
const posts =[
{
node: {
slug: "lorem"
}
},
{
node: {
slug: "ipsum"
}
}
];
posts.forEach((post, i) => {
// post is a single object. To access it's node, you need to use post.node
console.log("current post", post);
// To access the next post based on index
if(i<posts.length-1) {
console.log("Next node", posts[i + 1].node);
}
});
If you want to iterate on the next post based on index, use posts[index-1].node. As well make sure to check index, because for last element, index+1 will throw error.

Categories

Resources