Conditional $inc in MongoDB query - mongodb

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
}
})

Related

Adding new field to the document in the array of documents

I have mongo document like that:
{
"_id" : ObjectId("61b4cd63465cd7ace1e12341"),
"artist" : "Short",
"album" : "Track",
"tracks" : [
{
"title" : "100m",
"length" : 10
},
{
"title" : "200m",
"length" : 20,
"guest" : "Big Bad"
}
]
}
I'm trying to add field quest to the tracks array with title 100m.
So that a document looks like that:
{
"_id" : ObjectId("61b4cd63465cd7ace1e12341"),
"artist" : "Short",
"album" : "Track",
"tracks" : [
{
"title" : "100m",
"length" : 10,
"guest": : "John Travolta"
},
{
"title" : "200m",
"length" : 20,
"guest" : "Big Bad"
}
]
}
I was tryin got achive that using db.collection.update and $set, but no good results.
How can I achieve that?
You have to use positional operator $ like this:
db.collection.update({
"tracks.title": "100m"
},
{
"$set": {
"tracks.$.guest": "John Travolta"
}
})
This query tells to mongo "For the element into the tracks array where the title is 100m, insert the field guest with value John Travolta". And all of this using $ and the query stage "tracks.title": "100m"
Example here

$pull operator in MongoDB

{
"_id" : ObjectId("5badfada90fd543fd8aa7f96"),
"__v" : 0,
"deleted" : false,
"groups" : [
{
"group" : "grp",
"_id" : ObjectId("5bae09a601123357e58b66a2"),
"activities" : [
ObjectId("5bae09a601123357e58b66a3"),
ObjectId("5bae10de01123357e58b66a6")
]
},
{
"group" : "123",
"_id" : ObjectId("5bae0f1001123357e58b66a4"),
"activities" : [
ObjectId("5bae0f1001123357e58b66a5")
]
}
],
"nextActivityId" : 22,
"name" : "test",
"year" : "1",
"status" : "2",
"vision" : ObjectId("5bab2f4872acf42a81c124d0")
}
The Above Schema is a "Plan" Schema
I have to write a query for removing an Activity inside "activities" array. What will be the optimum solution for this? And how will I use $pull to achieve this
This was my solution, but it will delete the complete groups array
Plan.update({ _id: PLAN ID }, { $pull: { groups: { activities: ACTIVITY ID } } })
PLAN ID BEING: "_id" : ObjectId("5badfada90fd543fd8aa7f96"),
ACTIVITY ID FOR EXAMPLE BEING: ObjectId("5bae09a601123357e58b66a3")
Thank you!
You need to use the positional $ update operator.
db.Plan.update(
{ "_id" : PLAN ID },
{ "$pull": { "groups.$.activities": ACTIVITY ID } }
)
You can try this,
db.Plan.update({ _id: ObjectId("5badfada90fd543fd8aa7f96"),"groups.activities":{$in:[ ObjectId("5bae09a601123357e58b66a3") ]}},
{ $pull: { "groups.$.activities": ObjectId("5bae09a601123357e58b66a3") } });
The positional operator did not find the match needed from the query warning when use $ only update object.

MongoDB positional operator with nested arrays

Sample collection structure:
{
"_id" : ObjectId("57cfd62001ca2dd672cfebb1"),
"name" : "Category",
"parent" : ObjectId("57cfd5d101ca2dd672cfebb0"),
"posts" : [
{
"name" : "Post",
"author" : ObjectId("57cfd09401ca2dd672cfebac"),
"content" : "Some content.",
"comments" : [
{
"author" : ObjectId("57cfd09401ca2dd672cfebab"),
"content" : "First comment",
"rating" : 2
},
{
"author" : ObjectId("57cfd09401ca2dd672cfebac"),
"content" : "Second comment",
"rating" : 5
}
]
}
]
}
I would like to select all comments whose author is ObjectId("57cfd09401ca2dd672cfebab").
This query is working,
db.categories.find({ 'posts.comments.author':ObjectId("57cfd09401ca2dd672cfebab") })
but I would like to return only first matching comment with positional operator. Something like this is not working. Does MongoDB support positional operator with nested arrays?
db.categories.find({ 'posts.comments.author': ObjectId("57cfd09401ca2dd672cfebab") },
{ 'posts.comments.$': 1 })
You are having more than two level of nesting ...find() may not work ,instead try aggregation:-
> db.categories.aggregate([{$unwind:"$posts"},{$unwind:"$posts.comments"},
{$match:{"posts.comments.author":ObjectId("57cfd09401ca2dd672cfebab")}},
{$project:{_id:0,"posts.comments":1}}]).pretty()
Output:
{
"posts" : {
"comments" : {
"author" : ObjectId("57cfd09401ca2dd672cfebab"),
"content" : "First comment",
"rating" : 2
}
}
}

Mongodb Native Query

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"
}
}

How to read multikey index values in MongoDB?

I would like to have autocomplete feature that suggests keywords from database. If I use MongoDB and multikey index, I kind of already have these keywords in database, but can I access them somehow?
If I have following object in collection:
{
"title": "Some awesome title",
"keywords": [
"some",
"awesome",
"title"
]
}
And I have multikey index:
db.somecollection.ensureIndex({ "keywords" : 1 })
So index would contain following values:
"some"
"awesome"
"title"
If user enters "s" letter into autocomplete control, application should suggest "some" keyword. Can I search keywords from index or how should I do this?
You can choose to use aggregation framework:
DEV:history:PRI > db.test.find()
{ "_id" : ObjectId("51c37c0c20d107378f9af3cc"), "title" : "Some awesome title", "keywords" : [ "some", "awesome", "title" ] }
{ "_id" : ObjectId("51c37de420d107378f9af3ce"), "title" : "Some awesome title", "keywords" : [ "some", "awesome", "something" ] }
{ "_id" : ObjectId("51c37f1920d107378f9af3cf"), "title" : "Some awesome title", "keywords" : [ "something", "awesome", "someone" ] }
DEV:history:PRI > db.test.aggregate({$match : {keywords : /^som/}}, {$project:{keywords:1, _id : 0}}, {$unwind : "$keywords"}, {$match : {keywords : /^som/}}, {$group: {_id : '$keywords', count : {$sum : 1}}})
{
"result" : [
{
"_id" : "someone",
"count" : 1
},
{
"_id" : "something",
"count" : 2
},
{
"_id" : "some",
"count" : 2
}
],
"ok" : 1
}
Note: Multi-key index are not covered and there are some JIRA issues already filed. So, despite of using indexes the queries are not covered (for multi-key indexes)
We can optionally use the 'count' params to decide on the ordering in showing the auto-complete. If you don't require, remove from the query.