Update array object based on id? - node.js

I'm having a bit of a mongo issue. I was wondering if there was a way to do the following in a mongo console command rather then multiple find and update calls.
{
"_id" : ObjectId("50b429ba0e27b508d854483e"),
"array" : [
{
"id" : "1",
"letter" : "a"
},
{
"id" : "2",
"letter" : "b"
}
],
"tester" : "tom"
}
I want to update the object with this new array item
{
"id": "2",
"letter": "c"
}
I used this, addToSet is limited, it won't insert an item into the array if it is already there but it will not update an item based on an identifier. In this case I would really like to update this entry based on the id.
db.soup.update({
"tester": "tom"
}, {
$addToSet: {
"array": {
"id": "2",
"letter": "c"
}
}
});
This gives me:
{
"_id" : ObjectId("50b429ba0e27b508d854483e"),
"array" : [
{
"id" : "1",
"letter" : "a"
},
{
"id" : "2",
"letter" : "b"
},
{
"id" : "2",
"letter" : "c"
}
],
"tester" : "tom"
}
When what I really wanted was:
{
"_id" : ObjectId("50b429ba0e27b508d854483e"),
"array" : [
{
"id" : "1",
"letter" : "a"
},
{
"id" : "2",
"letter" : "c"
}
],
"tester" : "tom"
}

You can use the $ positional operator to do this:
db.soup.update(
{_id: ObjectId("50b429ba0e27b508d854483e"), 'array.id': '2'},
{$set: {'array.$.letter': 'c'}})
The $ in the update object acts as a placeholder for the first element of array to match the query selector.

Here you go:
> db.collection.insert( { array : [ { id : 1, letter : 'a' }, { id : 2, letter : 'b' } ], tester : 'tom' } );
> db.collection.findOne();
{
"_id" : ObjectId("50b431a69a0358d590a2f5f0"),
"array" : [
{
"id" : 1,
"letter" : "a"
},
{
"id" : 2,
"letter" : "b"
}
],
"tester" : "tom"
}
> db.collection.update( { tester : 'tom' }, { $set : { 'array.1' : { id : 2, letter : 'c' } } }, false, true );
> db.collection.findOne();
{
"_id" : ObjectId("50b431a69a0358d590a2f5f0"),
"array" : [
{
"id" : 1,
"letter" : "a"
},
{
"id" : 2,
"letter" : "c"
}
],
"tester" : "tom"
}
The trick lies in the false, true, false.
That is: true for upsert, false for update multiple.
For more details check out:
http://www.mongodb.org/display/DOCS/Updating#Updating-update%28%29

Related

update the nested array in mongodb using 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

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.

Update array with multiple conditions in mongodb

I have this document:
{
"_id" : ObjectId("5b673f525ef92ec6ef16504e"),
"events" : [
{
"name" : "Winner",
"map" : 0,
"something" : []
},
{
"name" : "Winner",
"map" : 2,
"something" : []
},
{
"name" : "DifferentName",
"map" : 2,
"something" : []
}
]
}
If I run the following update:
db.getCollection('test').updateOne({
"_id": ObjectId("5b673f525ef92ec6ef16504e"),
"events.name": "Winner",
"events.map": 2
},
{$push: {
"events.$.something": {
something: "test",
}
}
})
I get the bad result:
{
"_id" : ObjectId("5b673f525ef92ec6ef16504e"),
"events" : [
{
"name" : "Winner",
"map" : 0,
"something" : [
{
"something" : "test"
}
]
},
{
"name" : "Winner",
"map" : 2,
"something" : []
},
{
"name" : "DifferentName",
"map" : 2,
"something" : []
}
]
}
This is wrong, because "something" : "test" should be in the second element, where the map is equal to 2.
If I change the field "name" to "a" and run the same update, then I get the right result:
{
"_id" : ObjectId("5b673f525ef92ec6ef16504e"),
"events" : [
{
"a" : "Winner",
"map" : 0,
"something" : []
},
{
"a" : "Winner",
"map" : 2,
"something" : [
{
"something" : "test"
}
]
},
{
"a" : "DifferentName",
"map" : 2,
"something" : []
}
]
}
Now you can see, that "something" : "test" is in the right place (second event). Is this because I have used "name" and "name" is some kind of reserved keyword in Mongo?
When there are multiple conditions to match inside an array then the .Dot notation doesn't work with update query.
You need to use $elemMatch to match exact two fields inside an array
db.getCollection('test').updateOne(
{
"_id": ObjectId("5b673f525ef92ec6ef16504e"),
"events": { "$elemMatch": { "name": "Winner", "map": 2 }}
},
{
"$push": { "events.$.something": { "something": "test" }}
}
)

How to push new field in array mongodb

Imagine I have database like
{
"_id" : ObjectId("594994d1ab6c161168aa5969"),
"user_id" : ObjectId("594994d1ab6c161168aa5968"),
"active" : [
{
"type" : "active"
},
{
"type" : "inactive"
}
]
}
I want add to first object in active array . Here is result I expected
{
"_id" : ObjectId("594994d1ab6c161168aa5969"),
"user_id" : ObjectId("594994d1ab6c161168aa5968"),
"active" : [
{
"type" : "active",
"note": [{
content: 'here is content',
title : ' here is title'
}]
},
{
"type" : "inactive"
}
]
}
Here is code I tried
db.collection('..').update({'user_id' : ObjectId(userId)} ,
{$push:{ "active.0": "note": [{
content: 'here is content',
title : ' here is title'
}] } )
But I get The field 'active.0' must be an array but is of type object in document . Where is my wrong ? Please help
Starting with your document like this:
{
"_id" : ObjectId("594994d1ab6c161168aa5969"),
"user_id" : ObjectId("594994d1ab6c161168aa5968"),
"active" : [
{
"type" : "active"
},
{
"type" : "inactive"
}
]
}
You run the $push like this:
db.collection.update(
{ "_id" : ObjectId("594994d1ab6c161168aa5969") },
{ "$push":{ "active.0.note": { content: 'here is content', title : ' here is title' } } }
)
Which creates the new array within the first element like so:
{
"_id" : ObjectId("594994d1ab6c161168aa5969"),
"user_id" : ObjectId("594994d1ab6c161168aa5968"),
"active" : [
{
"type" : "active",
"note" : [
{
"content" : "here is content",
"title" : " here is title"
}
]
},
{
"type" : "inactive"
}
]
}
Everything here is cut and paste from my shell.

nodejs mongodb findAndModify exception: E11000 duplicate key error index

monogodb databse:
{ "title" : "A vs B ha",
"status" : 1,
"items" : [
{ "name" : "0",
"num" : 0,
"men" : [
{ "user" : "id1",
"score" : 300 },
{ "user" : "id2",
"score" : 1300 },
{ "user" : "id3",
"score" : 400 } ] },
{ "name" : "1",
"num" : 0,
"men" : [
{ "user" : "id11",
"score" : 3300 },
{ "user" : "id23",
"score" : 13400 },
{ "user" : "id3",
"score" : 4000 } ] },
{ "name" : "2",
"num" : 0,
"men" : [] } ],
"_id" : ObjectId( "538db59fa332f765c0f2c210" ) }
This Node.js code doesn't work:
collection.findAndModify(
{"_id": idSearch
,"items.name":sBetItem,"items.men.user":sUser}
,[]
, {
$set:{
"items.men.user":sUser}
,$inc: { "items.men.score": sScore }
}
, {new:true, upsert:true}
,function(err, docUser) {
if (err){
console.warn(err.message); // returns error if no matching object found
}else{
console.dir(docUser);
}
});
I want to search a player's score, if it doesn't exist, insert new;
if it already exist, increase his score number.
But it has error:exception: E11000 duplicate key error index

Resources