Mongodb Native Query - mongodb

My Data from Mongodb
{
"_id" : ObjectId("57d718ddd4c618cbf04772d6"),
"_class" : "io.core.entity.Layer",
"name" : "u2",
"layerMembers" : [
{
"permission" : "OWNER",
"user" : {
"_id" : ObjectId("57d440c3d4c60e2f13553216"),
"nameSurname" : "User 2",
"email" : "user2#email.com"
},
"isOwner" : true
},
{
"permission" : "EDIT",
"user" : {
"_id" : ObjectId("57d44050d4c62bfdc8a9fd30"),
"nameSurname" : "User 1",
"email" : "user#email.com"
},
"isOwner" : false
}
]
}
My queries;
db.getCollection('layer').find({$and: [{"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.permission":
"EDIT"}]})
db.getCollection('layer').find({$and: [{"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.isOwner":
false}]})
These queries, both of them found my data, but in my opinion, it should not get this data. Because query is 'AND' query and when the user id equals "57d440c3d4c60e2f13553216", permission is "OWNER" and "layerMembers.isOwner" is true.
And also this query can find my data.
db.getCollection('layer').find({"layerMembers.user._id":
ObjectId("57d440c3d4c60e2f13553216"), "layerMembers.isOwner": false})
What is the missing part ?

You should use $elemMatch (https://docs.mongodb.com/manual/reference/operator/query/elemMatch/) if you want to only return a document where you are trying to match multiple fields within a nested array.
something like:
{
"layerMembers":
"$elemMatch": {
"user._id": ObjectId("57d440c3d4c60e2f13553216"),
"permission": "EDIT"
}
}

Related

Mongodb $nin not working with nested array

I can't make $nin work with nested arrays, can you guys spot any issue with this query?
I'm basically trying to update the status of every document under items to "closed" in case their hash field is not in a list of hashes provided.
db.getCollection('projects').update({
name: 'test',
'issues.hash': { $nin: [
'8ff28fcc9cbf10c9b690bb331e5609efbd3c526be4f536ebca02cc51bd63eac7',
'd5368ad5658ec11103796255d127d26da7f3324cdedbd124bdd5db50812d588e',
'37298229097785ebc9d419cc1a3f13e0d090a15ceb9a8e6bea3505366902556d',
'fad290f2ddd0e097e4098c3b2c3d65611406cf208a3f86924d45c7736393b44b'
]}
},
{
$set: { "issues.$.status": "closed" }
}
)
This is the data:
{
"_id" : ObjectId("611bb4d2ee06769a5f6d906d"),
"name" : "test",
"issues" : [
{
"_id" : ObjectId("611bb4d20b2fb200167aa588"),
"status" : "open",
"hash" : "8ff28fcc9cbf10c9b690bb331e5609efbd3c526be4f536ebca02cc51bd63eac7"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa589"),
"status" : "open",
"hash" : "3b83e469049e46b16d3471a188d3f5e3ddbf6b296995a71765bbf17b7289e6ea"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58a"),
"status" : "open",
"hash" : "bef5f50628b669b9930b89cdc040361b9c8cc2b4aab3c2059c171786d38d507e"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58b"),
"status" : "open",
"hash" : "1b4a91eb5de97d6ad7493b6e1ffa48a2a648084b4af7b37916c723533a07c37c"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58c"),
"status" : "open",
"hash" : "bb64ba7b2612856dcd95c3ac2fad3f7368e5d463168545b12f4c869af56b55b7"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58d"),
"status" : "open",
"hash" : "1d5fc04739b10414dea8d327998df4f200f47ce57da243bd578d4ae102f2d670"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58e"),
"status" : "open",
"hash" : "d5368ad5658ec11103796255d127d26da7f3324cdedbd124bdd5db50812d588e"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa58f"),
"status" : "open",
"hash" : "37298229097785ebc9d419cc1a3f13e0d090a15ceb9a8e6bea3505366902556d"
},
{
"_id" : ObjectId("611bb4d20b2fb200167aa590"),
"status" : "open",
"hash" : "fad290f2ddd0e097e4098c3b2c3d65611406cf208a3f86924d45c7736393b44b"
}
]
}
And the is my result:
Updated 0 record(s) in 12ms
Thank you!
You have to use arrayFilters in this way:
db.collection.update({
"name": "test"
},
{
"$set": {
"issues.$[element].status": "closed"
}
},
{
"arrayFilters": [
{
"element.hash": {
"$nin": [
"8ff28fcc9cbf10c9b690bb331e5609efbd3c526be4f536ebca02cc51bd63eac7",
"d5368ad5658ec11103796255d127d26da7f3324cdedbd124bdd5db50812d588e",
"37298229097785ebc9d419cc1a3f13e0d090a15ceb9a8e6bea3505366902556d",
"fad290f2ddd0e097e4098c3b2c3d65611406cf208a3f86924d45c7736393b44b"
]
}
}
]
})
Example here.
Note that update query has the format: update(query, update, options) (Check the docs).
So with your find query mongo doesn't find anything. Check this example.
This is why you are telling mongo: "Give me a DOCUMENT where name is test and issues array NOT contains a field called hash with these values".
So, as mongo search by the whole document, there is no any document where hash value is not on the $nin array.
As another example to exaplain better: Check this example where hash value is 1. In this case, find query works because it matches two conditions:
There is a field name with value test
There is not any field hash into issues with values into $nin array.
You can use arrayFilters, like this:
db.collection.update({
"name": "test"
},
{
"$set": {
"issues.$[elem].status": "closed"
}
},
{
"multi": true,
"arrayFilters": [
{
"elem.hash": {
"$nin": [
"8ff28fcc9cbf10c9b690bb331e5609efbd3c526be4f536ebca02cc51bd63eac7",
"d5368ad5658ec11103796255d127d26da7f3324cdedbd124bdd5db50812d588e",
"37298229097785ebc9d419cc1a3f13e0d090a15ceb9a8e6bea3505366902556d",
"fad290f2ddd0e097e4098c3b2c3d65611406cf208a3f86924d45c7736393b44b"
]
}
}
]
})
Here is the working example: https://mongoplayground.net/p/8wZkmlBgKiq

Group by in mongoDB with property construction

I have a collection named Accounts like below data
/* 1 */
{
"_id" : ObjectId("5e93fea52f804ab99b54e4a2"),
"account" : "first",
"connect" : "Always",
"desc" : "first account feature first phase",
"status" : true
}
/* 2 */
{
"_id" : ObjectId("5e93fea32c804ab99b12e4d1"),
"account" : "second",
"connect" : "Sometimes",
"desc" : "second account feature first phase",
"status" : true
}
/* 3 */
{
"_id" : ObjectId("5e93fea52f804ab99b55a7b1"),
"account" : "first",
"connect" : "Sometimes",
"desc" : "first account feature second phase",
"status" : true
}
Trying to group and construct data in such a way that query should return a result like below structure
/* First Row */
"account" : "first",
[
{
_id:ObjectId("5e93fea52f804ab99b54e4a2")
"connect" : "Always",
"desc" : "first account feature first phase",
"status" : true
},
{
_id:ObjectId("5e93fea52f804ab99b55a7b1")
"connect" : "Sometimes",
"desc" : "first account feature second phase",
"status" : true
},
]
/* Second Row */
"account" : "second",
[
{
_id:ObjectId("5e93fea32c804ab99b12e4d1")
"connect" : "Always",
"desc" : "second account feature first phase",
"status" : true
},
]
Looking to group with Account and the respective account Row should have other related data of that Id.
What i tried
I tried writing below query
db.accounts.aggregate(
{
$match : {account : {$in: ["first", "second"]}}
}
,
{
$group : {
_id : "$account"
}
}
);
But this is working partially right returning list of accounts like first, second but not related properties.
Thanks
After $group use the $push accumulator to get the array of grouped data
db.accounts.aggregate([
{
$match: { account: { $in: ["first", "second"] } },
},
{
$group: {
_id: "$account",
data: { $push: "$$ROOT" },
},
}
]);

MongoDB querying references with additonal information

I am storing data of organizations in the following document structure:
{
"_id":ObjectId("52ffc33cd85242f436000001"),
"name": "NASA",
"users" : [
{
"_id" : ObjectId("5629f0b20fe85c57ed459913"),
"level" : "organization_lead"
},
{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"level" : "team_member"
}
]
}
Users are in another collection and look like this:
{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"email" : "bob#email.com",
"firstname" : "Bob",
"lastname" : "Green",
}
What would be the most efficient way to get a list of user documents belonging to a specific organization?
If I had only the _id's in the users array I would just pass that array to another query to get the users but what should I do in this situation? Or is there a better way to have a reference that has additional information?
Use the forEach() method of the find() cursor for the organisation collection to iterate over, access the documents in the loop and call the findOne() method to get the full user document of each user _id, as in the following example:
db.organisation.find({ "name": "NASA", "users.0": { "$exists": true } }).forEach(function(doc){
var updatedUsers = doc.users.map(function(u){
var user = db.users.findOne({"_id": u._id});
user["level"] = u.level;
return user;
}
doc.users = updatedUsers;
printjson(doc);
})
Use populate,
db.organisation.findOne({ "name": "NASA"}, function(err, response) {
db.Users.populate(response.user, {'path': _id, 'select': 'firstname lastname email'}, function(err, populatedUserData) {
console.log(populatedUserData);
});
});
Output will be,
[{
"_id":ObjectId("52ffc33cd85242f436000001"),
"name": "NASA",
"users" : [
{
"_id" : [{
"_id" : ObjectId("5629f0b20fe85c57ed459913"),,
"email" : "laurem#email.com",
"firstname" : "laurem",
"lastname" : "Ipsum"
}],
"level" : "organization_lead"
},
{
"_id" : [{
"_id" : ObjectId("5629ff550fe85c57ed459914"),
"email" : "bob#email.com",
"firstname" : "Bob",
"lastname" : "Green"
}],
"level" : "team_member"
}
]}]

Conditional $inc in MongoDB query

I have a survey system with documents like this:
{
"_id" : ObjectId("555b0b33ed26911e080102c4"),
"question" : "survey",
"subtitle" : "",
"answers" : [
{
"title" : "option 1",
"color" : "#FFEC00",
"code" : "opt1",
"_id" : ObjectId("555b0b33ed26911e080102ce"),
"votes" : 0,
"visible" : true
},
{
"title" : "option 2",
"color" : "#0bb2ff",
"code" : "opt2",
"_id" : ObjectId("555b0b33ed26911e080102cd"),
"votes" : 0,
"visible" : true
}
]
}
Now, I'm working on submit vote, so I need to increase 'votes' field for an specific survey (depending on option selected by user).
My problem is: I can have multiple documents like that, so how can I $inc field votes inside this array for an specific document? I tried this query (based on this website), but it didn't work:
db.bigsurveys.update(
{_id: ObjectId('555b0b33ed26911e080102c4'), 'answers.$.code' : 'opt1'},
{ $inc : { 'answers.$.votes' : 1 } }
)
The main problem here is that I can have multiple documents like this. Thanks in advance!
Use $elemMatch and postional operator $ to update query as :
db.bigsurveys.update({
"_id": ObjectId("555b0b33ed26911e080102c4"),
"answers": {
"$elemMatch": {
"code": "opt1"
}
}
}, {
"$inc": {
"answers.$.votes": 1
}
})

mongo remove item in document from array

i have the following document in my collection:
"_id" : "12345",
"name" : "test",
"users" : [
{
"name" : "spiderman",
"email" : "spiderman#spiderman.com",
"accepted" : true
},
{
"name" : "superman",
"email" : "superman#superman.com",
"accepted" : true
}
]
I would like to remove the user superman.
This is what i would like my final result to look like:
"_id" : "12345",
"name" : "test",
"users" : [
{
"name" : "spiderman",
"email" : "spiderman#spiderman.com",
"accepted" : true
}
]
Ive tried a few things but nothing worked so far. Any help is appreciated.
Thank you
You can use $pull
db.collection.update(
{ "users.name": "superman" },
{ $pull: { "users": {"name" : "superman"} } },
{ multi: false}
)