adding data to nested document : mongodb - database

I want to add new record within 'music'. My document looks similar to
{
"username": "erkin",
"email": "erkin-07#hotmail.com",
"password": "b",
"playlists": [
{
"_id": 58,
"name": "asdsa",
"date": "09-01-15",
"musics": {
"song-one":{
"song-one": "INNA - Cola Song (feat. J Balvin)",
"duration": "3.00"
},
"song-two":{
"song-two": "blabla",
"duration": "3.00"
}
}
}
]
}
After navigating to "music" and then using $set to add/update multiple records at once. But new records is getting added in lexicographical manner(behaviour of $set).
I'm using query similar to (so in my case song-four is coming before song-three) :
db.getCollection('myCollection').update({username:"erkin"},{$set:{"playlists.musics.song-three":{...},"playlists.musics.song-four":{...}}})
Is there any way I can add new records to that location in a way my $set query is arranged ?

As playlists is an array:
Option 1: Update the first document in playlists.
Specify the index: 0 for the first document in playlists.
playlists.0.musics.song-three
db.collection.update({
username: "erkin"
},
{
$set: {
"playlists.0.musics.song-three": {
"song-three": "song-three"
},
"playlists.0.musics.song-four": {
"song-four": "song-four"
}
}
})
Sample Demo on Mongo Playground (Option 1)
Option 2: Update all documents in playlists.
With $[] all positional operator.
playlists.$[].musics.song-three
db.collection.update({
username: "erkin"
},
{
$set: {
"playlists.$[].musics.song-three": {
"song-three": "song-three"
},
"playlists.$[].musics.song-four": {
"song-four": "song-four"
}
}
})
Sample Demo on Mongo Playground (Option 2)
Option 3: Update specified document in playlists.
With $[<identifier>] filtered positional operator.
playlists.$[playlist].musics.song-three
db.collection.update({
username: "erkin"
},
{
$set: {
"playlists.$[playlist].musics.song-three": {
"song-three": "song-three"
},
"playlists.$[playlist].musics.song-four": {
"song-four": "song-four"
}
}
},
{
arrayFilters: [
{
"playlist._id": 58
}
]
})
Sample Demo on Mongo Playground (Option 3)

Related

Add new column to multi nested array in mongo db

"ParentType": {
"Food": [
{
"Name": "Burger",
"FoodId": "5e3abe145c1bfb31b4e335de",
"Price": 0,
"Quantity": 1,
"SubCategory": 0
}
],
"Inventory": [
{
"Name": "Small Popcorn",
"InventoryId": "5e3a64245c1bfb31b4e335b7",
"Price": 0,
"Quantity": 1,
"SubCategory": 0
}
]
}
I need to add UOM as new column only for Inventory array.I have used aggregate as below but collection is not getting updated.Pls help me with adding this new Column in mongodb
db.Concession.aggregate([
{
$addFields: { ParentType.Inventory.UOM: "null" }
}
])
add UOM to all eliment in Inventory
db.collection.update(
{},
{ $set: { 'ParentType.Inventory.$[].UOM':''} }
)
Option 1: ( Update/$set 3.6+ )
db.collection.update({},
{
$set: {
"ParentType.Inventory.$[].UOM": null
}
},
{
multi: true
})
Explained:
Use update() operation with positional operator $[] ( mongoDB 3.6+ )
Use option multi to update all documents in collection matching the filter criteria
Playground
Option 2: ( Update/aggregation 4.2+)
db.collection.update({},
[
{
$addFields: {
"ParentType.Inventory": {
"$map": {
input: "$ParentType.Inventory",
as: "i",
in: {
"$mergeObjects": [
"$$i",
{
UOM: null
}
]
}
}
}
}
}
],
{
multi: true
})
Explained:
Use update with aggregation pipeline ( mongoDB 4.2+ )
In aggregation use the addFileds with mergeObjects so you add the new fields to the array element.
Use multi:true to affect all documents in collection matching the filter criteria
Playground 2

How can I update a multi level nested array in MongoDB?

How can I update a record in a document with multiple levels of array nesting?
My document structure is the following:
{
"_id": "5bfa09f0a0441f38d45dcc9c",
"nombre": "PROYECTO MAIN",
"area": "Sistemas",
"fecha": "27/01/2018",
"reuniones": [
{
"_id": "5bfa09f0a0441f38d45dcc99",
"objetivo": "Objetivo MODIFICADO",
"fecha": "25/10/2018",
"participantes": [
{
"nomina": 1,
"nombre": "MODIFICADO",
"rol": "rol",
"area": "area",
"firma": "url/imagen.jpg"
},
{
"nomina": 2,
"nombre": "nombre 2",
"rol": "rol",
"area": "area",
"firma": "url/imagen.jpg"
}
]
}
],
"_class": "proyecto"
}
Using the following query, returns me the document mentioned above.
db.proyectos.find({
_id:ObjectId("5bfa09f0a0441f38d45dcc9c"),
"reuniones._id":ObjectId("5bfa09f0a0441f38d45dcc99"),
"reuniones.participantes.nomina":2
})
I want to update the firma field of participant with nomina 2.
Since Mongo 3.6, you can update multi-nested arrays by combining the following operators:
$set (to update a specific field)
$[] (to match any item in an array)
$[<identifier>] (to match specific items in an array)
Example
Here's how you can update a specific proyectos document that has a reuniones array that has a participantes array that has an object with the field nomina equal to 2:
// update a specific proyectos document
// that has a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2
db.proyectos.update({
_id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
$set: {
"reuniones.$[].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"j.nomina": 2
}
]
})
If you wanted to limit your query to a specific reunion, you can do:
db.proyectos.update({
_id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
$set: {
"reuniones.$[i].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"i._id": ObjectId("5bfa09f0a0441f38d45dcc99")
},
{
"j.nomina": 2
}
]
})
To update all proyectos satisfying the above condition, just omit the _id query:
// update all proyectos
// that have a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2
db.proyectos.update({}, {
$set: {
"reuniones.$[].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"j.nomina": 2
}
]
})

Push object into array if exists otherwise set object in MongoDB

This is the document I currently have:
{
"_id": "",
"title": "My Watchlist",
"series": [{
"seriesId": 1,
"following": true,
"seasons": []
}, {
"seriesId": 1,
"following": false,
"seasons": []
}]
}
As you can see there are currently 2 objects with the seriesId 1, but with a different following boolean.
If the query matches with _id it should push the new object into series, if within the "series"-array an object with the same "seriesId" already exists it should change the fields within that object, instead of adding a new object.
I currently have the following query:
users.update(
{"_id": req.body.userId},
{
"$push": {
"series": {"seriesId": req.body.seriesId, "following": req.body.following}
}
}, (err, data) => {
if (err)
next(err);
});
If I use $set it does not add the object if it didn't originaly exist yet, and as far as I know you cannot both use $push and $set?
Can this be fixed in any way or do I have to rethink my Schema?
You can use two update query :
if _id is found and seriesId is not in the array, add the new item to the array :
db.series.update({
"_id": req.body.userId,
"series": {
"$not": {
"$elemMatch": {
"seriesId": req.body.seriesId
}
}
}
}, {
$addToSet: {
series: {
"seriesId": req.body.seriesId,
"following": req.body.following,
"seasons": []
}
}
}, { multi: true });
if _id is found and seriesId is found in the array, update the array item :
db.series.update({
"_id": req.body.userId,
"series.seriesId": req.body.seriesId
}, {
$set: {
"series.$.following": req.body.following
}
}, { multi: true });

Only one element returned in array

I am trying to find elements from my MongoDB database with meteor.
I managed to filter and go through the structure of my array, but the result is a single element, and not all the elements matching the criteria.
Query :
var json = Tests1VerlIR.find({}, {fields: {entries: {$elemMatch: {'payload.id': {$eq: this.params._id}} } } }).fetch();
this.response.setHeader('Content-Type', 'application/json');
this.response.end(JSON.stringify(json));
Data Structure :
{"entries":
[{"method":"POST",
"source":"ex",
"path":"/ex",
"time":1464615406900,
"payload":
{"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"},
"_id":"574c41ee578d01af3664cbaf"},
{"method":"POST",
"source":"ex",
"path":"/ex",
"time":1464615406900,
"payload":
{"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"},
"_id":"574c41ee578d01af3664cbaf"}, {...}]}
Response :
[
{
"_id":
{
"_str": "576155d7a605348159cd1f1a"
},
"entries":
[
{
"method": "POST",
"source": "ex",
"path": "/ex",
"time": 1464615406900,
"payload":
{
"slot_frame_number":"4",
"slot_HTUTemp":"2306",
"data":"0400f008561655270209a314",
"slot_BMEPres":"10069",
"slot_HTUHumi":"5283",
"slot_BMETemp":"2288",
"time":"1464615404",
"device":"79",
"slot_BMEHumi":"5718",
"signal":"7.22",
"id":"2"
},
"_id": "574c41ee578d01af3664cbaf"
}
]
}
]
You cannot return multiple elements of an array matching your criteria in any form of a basic .find() query. To match more than one element you need to use the .aggregate() method instead.
refer this link.
Tests1VerlIR.aggregate([
{ "$match": { "entries.payload.id": "2" } },
// Unwind the array to denormalize
{ "$unwind": "$entries" },
// Match specific array elements
{ "$match": { "entries.payload.id": "2" } },
// Group back to array form
{ "$group": {
"_id": "$_id",
"entries": { "$push": "$entries" }
}}
])
Solution :
var json = Tests1VerlIR.aggregate({"$unwind": "$entries"}, {$match: {'entries.payload.id': this.params._id} });

Is there a way to push a sub document into mongodb array only if the condition is satisfied?

i am pushing sub documents into an array.
Basically the subdocs are something like this:
{
id:"someId",
date:Date
}
i want to add new subdoc only if the theres no other subdoc with matching id.I found $addToSet modifier on mongodb documentation but i am not sure if it can just check a key inside a sub document rather than comparin entire array item to another one.
Is there any way to do this in single query or anyway should i go with 2 queries?
You can do this in a single atomic update operation. Suppose your collection has the following documents:
Mongo shell
db.test.insert([
{
"_id": 1,
"items": [
{ "id": 1, "date": new Date("2016-05-20") },
{ "id": 2, "date": new Date("2016-05-21") }
]
},
{
"_id": 2,
"items": [
{ "date": new Date("2016-05-22") }
]
}
])
Then the following update statement in mongo shell will update the document that has the items subdoc which does not have the id key by adding the new sub document { "id": 3, "date": new Date() } to the items array:
db.test.update(
{ "items.id": { "$exists": false } },
{
"$push": {
"items": { "id": 3, "date": new Date() }
}
}
)
Querying the test collection
> db.test.find().pretty()
{
"_id" : 1,
"items" : [
{
"id" : 1,
"date" : ISODate("2016-05-20T00:00:00Z")
},
{
"id" : 2,
"date" : ISODate("2016-05-21T00:00:00Z")
}
]
}
{
"_id" : 2,
"items" : [
{
"date" : ISODate("2016-05-22T00:00:00Z")
},
{
"id" : 3,
"date" : ISODate("2016-05-23T09:33:15.913Z")
}
]
}
To add a new subdoc only if the there's no other subdoc with a matching id, you only need one update operation where you can specify the matching condition
in the update query document.
The following update operation will add a subdocument with id = 4 to the array since there is no matching array element in the existing document:
db.test.update(
{ "items.id": { "$ne": 4 } },
{
"$push": {
"items": { "id": 4, "date": new Date() }
}
}
)
For an exclusive update where you just want to add the subdocument if there is an id field AND the given id does not match, then include the condition together with the equality check:
db.test.update(
{
"items.id": {
"$exists": true,
"$ne": 4
}
},
{
"$push": {
"items": { "id": 4, "date": new Date() }
}
}
)

Resources