update the nested array in mongodb using node js - node.js

I need to update a particular element of the nested array in mongoDB
My mongoDB data looks like below. I need to match the value accessid and name to update the status. The input content has
{"accessid" : 1627047023995, "name" : Name 09, "status" : 100 }
The input content may belong to any level
{
"_id" : ObjectId("60fac46ffcbf5287248460a9"),
"levelone" : [
{
"level" : [
{
"name" : "Name 01",
"status" : 5
},
{
"name" : "Name 02",
"status" : 0
},
{
"name" : "Name 03",
"status" : 0
}
],
"accessid" : "1627047023995"
},
{
"level" : [
{
"name" : "Name 09",
"status" : 5
},
{
"name" : "Name 15",
"status" : 3
}
],
"accessid" : "1627047023995"
}
],
"createdAt" : ISODate("2021-07-23T13:30:23.995Z")
}
I have tried to update the status, but it is updating only the first index value - name: Name 01 status. Please guide to resolve the issue.
collections.updateOne({
'levelone.level.accessid': accessid,
'levelone.level.name': name
}, { '$set': { 'levelone.$.level.status': status } }).exec();

you can use arrayFilters positional update,
query with $elemMatch to filter the main document
arrayFilters to define a variable for accessid and b for name
await collections.updateOne({
levelone: {
$elemMatch: {
accessid: accessid,
"level.name": name
}
}
},
{
$set: {
"levelone.$[a].level.$[b].status": status
}
},
{
arrayFilters: [
{ "a.accessid": accessid },
{ "b.name": name }
]
})
Playground

Related

Mongo: filter documents from multiple collections and merge

I am new to mongo and NodeJS and have a use case where I want to get filtered results from multiple collection.
Advance apologies for the long post.
for ex:
collectionA
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
}
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
}
}
collectionB: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "AttB_Name",
"val" : "Coll_B_AttB_Val_Bar"
}
]
}
CollectionC: Some attributes are not present for all the documents and hence optional
{
"_id" : "foo#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com"
"AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
],
"AttributeB" : [
{
"name" : "Coll_C_AttB_Name",
"val" : "Coll_C_AttB_Val_Bar"
}
]
}
I know Collection B and C schema looks the same but the purpose is different and they have to be different. DB design is not the question so I would appreciate if do not put all the focus on it.
Query:
Assume there is another user (Alan) with same attributes present as Bar that exist in the collection but is not living nearby the location of Bar.
The query I am trying to build on top of these is,
Find people living nearby from CollectionA
And Collection B, if AttributeA exist and have an element with name: AttA_Name
And in Collection C, if AttributeA exist and have an name: Coll_C_AttA_Name
In the above case I am expecting a result as
{
"_id" : "foo#gmail.com",
"name" : "Foo",
"location" : {
"coordinates" : [
-122.420170,
37.780080
],
"type" : "Point"
},
"collectionB_AttributeA" : [
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Foo"
},
{
"name" : "AttA_Name1",
"val" : "Coll_B_AttA_Val_Foo"
}]
,
"collectionC_AttributeA" : [
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Foo"
}]
},
{
"_id" : "bar#gmail.com,
"name" : "Bar",
"location" : {
"coordinates" : [
-122.420060,
37.780180
],
"type" : "Point"
},
"collectionB_AttributeA":[
{
"name" : "AttA_Name",
"val" : "Coll_B_AttA_Val_Bar"
},
{
"name" : "AttA_Name2",
"val" : "Coll_B_AttA_Val_Bar"
}
],
"collectionC_AttributeA":[
{
"name" : "Coll_C_AttA_Name",
"val" : "Coll_C_AttA_Val_Bar"
}
]
}
There is one way of doing is in parts:
query Collection A and get the nearby people
Loop through the result of 1 and find in CollectionB if they have AttributeA and an element with name AttA_Name and eliminate if they don't match.
Loop through the filtered results from 2 and find in CollectionC if they have AttributeA and and element with name Coll_C_AttA_Name and if they don't eliminate such documents.
Is there a way I can use aggregate to build this query as one? I tried reading and trying the aggregate but seems like my understanding is incomplete.
let result = await CollectionASchema.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [ Number(long) , Number(lat) ] },
distanceField: "dist.calculated",
minDistance: 0,
maxDistance: radiusinmetres,
spherical: true
}
},
{
$lookup:
{
from: 'collectionB',
pipeline: [
{ $match : { $and: [{ AttributeA :{$exists: true}}, { [category]: { $elemMatch: { name: “AttA_Name” } } }] }},
{ $project: { AttributeA: 0 } }
],
as: "collectionB_AttributeA"
}
}
])
If you can explain if this is possible or let me know off this is the right approach that would be helpful.

How to update nested array without ID in object

I know this has been asked a number of times before but I can't seem to find the answer, How to update in nested array but objet in nested array without id???
const hasil = await Setting.update(
{ _id: Id, 'value.name': req.body.name },
{ "$set": { 'value.value': req.body.value } }
)
{
"_id" : 1234567,
"key" : "version",
"name" : "Collection Version",
"value" : [
{
"name" : "categories",
"value" : 7
},
{
"name" : "tag",
"value" : 1
},
{
"name" : "article",
"value" : 3
},
],
}

MongoDB Update nested object of objects value [duplicate]

This question already has answers here:
MongoDB Add an object to a nested object with condition [duplicate]
Updating a Nested Array with MongoDB
(2 answers)
Closed 4 years ago.
I have the format of:
{
"_id" : ObjectId("5af44cfbe2e96c58ec402efb"),
"username" : "egealpay2",
"email" : "egealpay2#gmail.com",
"fullName" : "ege",
"pnumber" : "",
"oneSignal" : "d427dcdf-7939-4ada-a035-be74e1e45091",
"friends" : [
{
"email" : "baransrc#gmail.com",
"status" : 2
}
],
"alarms" : [
{
"id" : "2",
"title" : "before",
"location" : "default",
"startTime" : "2018-05-16\t\t\t16:29",
"endTime" : "16:29\t\t\t17 - 05 - 2018",
"remindAt" : "17:29\t\t\t15 - 05 - 2018",
"privacy" : "0",
"userORJoinedAlarm" : "1",
"eventJoiners" : [
{
"email" : "ilkersadya#sabanciuniv.edu",
"status" : 1
},
{
"email" : "ilkercankayasss#sabanciuniv.edu",
"status" : 1
},
{
"email" : "ilkearcankaya#sabanciuniv.edu",
"status" : 1
},
{
"email" : "iaaalkercankaya#sabanciuniv.edu",
"status" : 1
}
],
"comments" : [ ]
}
]
}
i would like to set status: 2 of "email" : "ilkersadya#sabanciuniv.edu", its under"alarms:" , "eventJoiners" :which has an id of 2 as"id"`
I have tried using push with $ but couldnt manage to get this working and its been bugging me over 2 hours.
Update i had tried thanks to #Ashish:
dbo.collection("users").findOne( { email: userId } , function(errZer, addedZer) {
dbo.collection("users").findOneAndUpdate( {email: addedID, "alarms.id": eventIDGiv, alarms: { $elemMatch: { id: '2', eventJoiners: { $elemMatch: { email: addedID } } }} },
{ $set: { "alarms.$.eventJoiners.$.status": '2' } , function(err, added) {
got the error
(node:9334) UnhandledPromiseRejectionWarning: MongoError: Too many positional (i.e. '$') elements found in path 'alarms.$.eventJoiners.$.status'
Positional operator ($) can be used only for one level of nested arrays. In your case you have to specify conditions both for alarms and eventJoiners. To do that you can use $[< identifier >] syntax (which is available in MongoDB 3.6+):
db.collection.update(
{ _id: ObjectId("5af44cfbe2e96c58ec402efb") },
{ $set: { "alarms.$[elem1].eventJoiners.$[elem2].status": "2" } },
{ arrayFilters: [ { "elem1.id": "2" }, { "elem2.email": "ilkersadya#sabanciuniv.edu" } ]})
In this case identifiers elem1 and elem2 are used as placeholders for conditions specifed in arrayFilters section.

want to update only value element of specific key on mongodb

I have a dataset like this:
{
"_id" : ObjectId("5a7bee68996b551034015a15"),
"sequenceid" : 1,
"fruit" : [
{
"name" : "#APPLE",
"value" : 2
},
{
"name" : "#BANANA",
"value" : 1
},
{
"name" : "#ORANGE",
"value" : 5
}
}
want to update only Apple value i.e from 2 to 25. Expected result will be:
{
"_id" : ObjectId("5a7bee68996b551034015a15"),
"sequenceid" : 1,
"fruit" : [
{
"name" : "#APPLE",
"value" : 25
},
{
"name" : "#BANANA",
"value" : 1
},
{
"name" : "#ORANGE",
"value" : 5
}
}
I tried the code but this will replace all entry and do only one entry. My code is
db.Collection.update({'sequenceid': 1}, {$set: {'fruit' : {'name': '#APPLE', 'value': parseFloat(25)}}}, function(error, result){
if(error){
console.log('error');
} else {
console.log('success');
}
});
It can produce the result:
{
"_id" : ObjectId("5a7bee68996b551034015a15"),
"sequenceid" : 1,
"fruit" : [
{
"name" : "#APPLE",
"value" : 25
}
}//Delete all my rest entry
How I can Do this. I am a newbie on MongoDB
This will update only the first occurrence of record.For reference MongoDB - Update objects in a document's array (nested updating)
db.collection.update({ _id: ObjectId("5a7bf5586262dc7b9f3a8422") ,"fruit.name" : "#APPLE"},
{ $set:
{
"fruit.$.value" : 25
}
})
If you are writing JavaScript query then you can update like this
db.collection.find({'sequenceid': 1}).forEach(function(x){
x.fruit.forEach(function(y){
if(y.name=="#APPLE")
{
y.value = 25
}
})
db.collection.update({_id:x._id},x)
})
db.Collection.update({
_id: ObjectId("5a7bee68996b551034015a15"),
"fruit": {
$elemMatch: {
"name": "#APPLE"
}
}
}, {
$set: {
"fruit.$.value": 25
}
})
In above update operation $elemMatch operator is used to search a value in an array and in $set stage positional operator $ is used to update value of specific key belonging to an array element

Node : Mongoose Updating User Schema with arrays

Here is my User Schema
{
"user_collection":[
{
"_id":"xxx",
"name":"NAME",
"prescription":
{
"doctor_id":
[{
"_id":"xxx",
"medicine_id":"MEDICINE_ID",
}]
},
"meal":{
"meal_name":{
"start_time":"START_TIME",
"end_time":"END_TIME"
}
},
"created_at":"CREATED_AT",
"updted_at":"UPDATED_AT"
}
]
}
Note : _id given just for understanding
I need to insert document inside the prescription array. Here is the condition
If the new doctor_id is given, it should add in the prescription array like
{
"_id" : ObjectId("5813288eaa0f1231de477d92"),
"name" : "andrew",
"prescription" : [
{
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0528"),
"medicine_id" : "10011241343"
}
],
"_id" : ObjectId("58143d484e26a229873b0527"),
"doctor_id" : "5813221ace684e2b3f5f0a6d"
}
]
}
And if i given the doctor_id that already exists it should add like
{
"_id" : ObjectId("5813288eaa0f1231de477d92"),
"name" : "andrew",
"prescription" : [
{
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0528"),
"medicine_id" : "10011241343"
}
],
"prescription" : [
{
"_id" : ObjectId("58143d484e26a229873b0529"),
"medicine_id" : "10011241349"
}
],
"_id" : ObjectId("58143d484e26a229873b0527"),
"doctor_id" : "5813221ace684e2b3f5f0a6d"
}
]
}
What i have tried is
dbModel.user.update({
_id: req.body.user_id
}, {
$set: {
prescription: [ { "doctor_id" : req.body.doctor_id, "prescription" : [
{
"medicine_id" : req.body.medicine_id
}]} ],
}
}, {
upsert: true
}, function(err) {
if (err) {
res.status(202).json({
"success": "0",
"message": err
})
} else {
res.status(200).json({
"success": "1",
"message": "Prescription given successfully"
});
}
})
I don't know how to check whether the doctor_id already exists and if it does not exists it should add a new array, and if it exists it should add inside the existing arrays
Take a look in this answer.
But basically you can use the $ operator which identifies an element in an array.
You can see here some mongodb array operators.

Resources