Add key value on all objects inside an array in MongoDB - mongodb

I have a dataset like this on MongoDB:
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b7"),
arrayHolder: [
{name: 'Peter'},
{name: 'John'}
]
},
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b8"),
arrayHolder: [
{name: 'Harry'},
{name: 'Nik'}
]
}
Now I want to add one more key values to all objects under arrayHolder objects. I am sharing the Expected Output:
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b7"),
arrayHolder: [
{name: 'Peter', valid: true },
{name: 'John', valid: true}
]
},
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b8"),
arrayHolder: [
{name: 'Harry', valid: true},
{name: 'Nik', valid: true}
]
}
For this I wrote the query but that query will add the new object inside the array rather than adding one more key-value under the objects.
My Query is:
db.Collection.updateMany({}, {$push: {arrayHolder: {$each: {valid: true}}}})
This Query will add the new Objects inside an array. I am sharing the output which I am getting after this query run:
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b7"),
arrayHolder: [
{name: 'Peter'},
{name: 'John'},
{valid: true}
]
},
{
"_id" : ObjectId("5f7b02a197cca91d3476a3b8"),
arrayHolder: [
{name: 'Harry'},
{name: 'Nik'},
{valid: true}
]
}
Is there anyone who guide me where I have done the mistakes and how to fire the proper query so that expected output will achieved.
Thanks in advance for the people who interacted with this problem

You can use all positional operator $[] to do that:
db.Collection.updateMany({}, {$set: {'arrayHolder.$[].valid': true}})

Related

How to retrieve object values with same key inside an array

I'm trying to get (filter) all the objects from a document array that match the same key.
Document Schema example:
{
...
country: "ES",
aut_comms:
[
...
{name: "Aragon", province: "Huesca"},
{name: "Aragon", province: "Teruel"},
{name: "Aragon", province: "Zaragoza"},
{name: "Madrid", province: "Madrid"}
...
]
}
If it is possible, im tying to retrieve from the query only the values from the objects that match the same key. Resulting in an array composed like : ["Huesca", "Teruel", "Zaragoza"]
An Array of objects that match the filter will also do the trick:
[
{name: "Aragon", province: "Huesca"},
{name: "Aragon", province: "Teruel"},
{name: "Aragon", province: "Zaragoza"}
]
Thanx
You will be able to get this array by first unwinding the array and then manipulating it
db.demo.aggregate([
{
$unwind:"$aut_comms"
},
{
$match:{"aut_comms.name":"Aragon"}
},
{
$group:{
_id:null,
result: {$push:"$aut_comms.province"}
}
}
])
Edit
It is indeed possible to do such query and output in your expected format. You can do either $unwind or $match first. Personally, I prefer to do a $match first as it would limit the number of (unnecessary) documents generated by the $unwind operation.
db.getCollection('col').aggregate([
{$match: {"aut_comms.name": "Aragon"}},
{$project: {_id: 0, "aut_comms": 1}},
{$unwind: "$aut_comms"},
{$match: {"aut_comms.name": "Aragon"}},
{$project: {"province": "$aut_comms.province"}},
{$group: {
_id: null,
province: {$push: "$province"}
}}
])
The output will be:
/* 1 */
{
"_id" : null,
"province" : [
"Huesca",
"Teruel",
"Zaragoza"
]
}

Mongo Chaining filters

I'm learning mongodb and java and have the following question, is it possible to chain filters?
So my example document in mongo is as follows
{"_id" : "...."
"name" :"Joe",
"roles" : ["A","B", "C"],
"value" : 1000
}
Can i do an update using a filter which will update depending on whether the document in mongo contain the roles
example my
listCriteria = ["B","D","E"]
so update this document if it has the roles B, D, E, update the value to 2000
In java I know I can use filters
Bson filter = Filters.eq("name", "Joe");
Filters.in("roles", roles);
.....
this.collection.updateOne(filter, updatedDocument...)
How can I chain it so that it updates the document with name "Joe" only if the roles in the documents contains atleast one in the list criteria
Must contain all 3 roles - use $all query operator:
db.people.update(
{
name: "Joe",
roles: {$all: ["B", "D", "E"]}
},
{
$set: {value: 2000}
}
);
Must contain any of 3 roles - use $in query operator:
db.people.update(
{
name: "Joe",
roles: {$in: ["B", "D", "E"]}
},
{
$set: {value: 2000}
}
);
About generally chaining filters, you can use $and query operator:
db.people.update(
{
$and: [
{name: "Joe"},
{roles: "B"},
{roles: "D"},
{roles: "E"}
]
},
{
$set: {value: 2000}
}
);

MongoDB filter inner array of object

I have one document like this:
-document: users-
{
"name": "x", password: "x" recipes:
[{title: eggs, dificult: 1},{title: "pizza" dificult: 2}],
name: "y", password: "y" recipes: [{title: "oil", dificult: 2},{title: "eggandpotatoes" dificult: 2}]
}
I want to get all recipes filtering by title and dificult
I have tried some like this
db.users.find({$and: [{"recipes.title": /.*egg.*/},{"recipes.dificult": 2}]},
{"recipes.title": 1,"recipes.dificult": 1}).toArray();
this should return
{title: "eggandpotatoes" dificult: 2}
but return
{title: eggs, dificult: 1}
{title: "eggandpotatoes" dificult: 2}
I would like once the filter works, limit the result with start: 2 and end: 5
returning from the 2 result the next 5.
Thanks in advance.
You can use the $filter aggregation to filter the recipes and $slice to limit the results. It will give you everything you are looking expect but regex search which is not possible as of now.
db.users.aggregate([{
$project: {
_id: 0,
recipes: {
$slice: [{
$filter: {
input: "$recipes",
as: "recipe",
"cond": {
$and: [{
$eq: ["$$recipe.title", "eggandpotatoes"]
}, {
$eq: ["$$recipe.dificult", 2]
}]
}
}
}, 2, 3]
}
}
}]);
If you need to find out regular expression in title then use $elemMatch as below :
db.users.find({"recipes":{"$elemMatch":{"title": /.*egg.*/,"dificult": 2}}}, {"recipes.$":1})
One thing I mentioned here if your recipes array contains some thing like this
"recipes" : [ { "title" : "egg", "dificult" : 2 }, { "title" : "eggand", "dificult" : 2 } ]
then $ projection return only first matched array objcect in above case it will be
"recipes" : [ { "title" : "egg", "dificult" : 2 } ]
If you need this both array then go to #Sagar answer using aggregation

MongoDB Returning One Nested Document from a Result

I have a MongoDB collection called "ballots" and it looks like this:
{
"_id" : "msw9ofwQSj58qiPvY",
"ballotName" : "This is the ballot name",
"votes" : [
{ "unitNumber" : "30", "voteResult" : "No", "voteDate" : ISODate("2015-02-24T05:03:22.937Z") },
{ "unitNumber" : "30", "voteResult" : "Yes", "voteDate" : ISODate("2015-02-24T05:20:02.479Z") }
]
}
I want to see only the LATEST "votes.voteResult" for this _id and by unitNumber:30. I try:
db.ballots.find(
{ $and: [
{_id: 'msw9ofwQSj58qiPvY'},
{'votes.unitNumber': '30'}
] },
{'votes.voteResult': 1, 'votes.voteDate': 1, _id: 0} )
Results:
{
"votes" : [
{
"voteResult": "No",
"voteDate" : ISODate("2015-02-24T05:03:22.937Z")
},
{
"voteResult": "Yes",
"voteDate" : ISODate("2015-02-24T05:20:02.479Z")
}
]
}
Looks good, however I only want ONE "voteResult" to return. I only want the latest one. I cannot seem to figure out how to get one of the nested result sets, AND ensure it is the most recent one. If it's any help, I am using Meteor/javascript which perhaps can handle the coding logic of this, but hoping a simple MongoDB query can just give me the result.
Any help is greatly appreciated. Thanks.
You can use sort and limit for these things:
db.ballots.find(
{ $and: [
{_id: 'msw9ofwQSj58qiPvY'},
{'votes.unitNumber': '30'},
] },
{'votes.voteResult': 1, 'votes.voteDate': 1, _id: 0}
).sort({'votes.voteDate':-1).limit(1);
You get both back, but if you sort them by voteDate and return the first one, you should have the one you want.
You might also be able to do it all server-side using aggregate instead of find:
db.ballots.aggregate(
{$match :
{$and: [
{_id: 'msw9ofwQSj58qiPvY'},
{'votes.unitNumber': '30'},
]}
},
{$unwind: "$votes"},
{$sort: {'votes.voteDate': -1}},
{$limit: 1},
{$project: {'votes.voteResult': 1, 'votes.voteDate': 1, _id: 0}}
);

mongo: update matched elements of array that is in other array

I have next schema of mongo document:
{
"array1" : [
{
"array2" : [
{
"id" : 1,
"field" : 2
}
]
}
]
}
I want to find elements in array2 with {id: 1} and update its "field". I tried next:
db.filmCitation.update({ "array1.array2": {$elemMatch: {"id": 1, field: {$gte: 2}} } }, {$set: {"array1.array2.field": 23})
But I must specify right index in arrays. For one array can be used "$". And what can I do when needs to find in several arrays?
Thanks!