Adding new field to the document in the array of documents - mongodb

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

Related

How to query for and delete embedded objects in an array field in MongoDB?

I am trying to run an update command that finds an object in an array field for all documents and then pulls it from that array field for all documents. I have tried the below commands, which do not return any documents (nMatched: 0).
db.users.update({"likedQuizzes.quiz": { $elemMatch: quizObj}},{$pull: {"likedQuizzes.quiz": quizObj }});
db.users.update({"likedQuizzes": { $elemMatch: quizObj}},{$pull: {"likedQuizzes": quizObj }});
In the above cases quizObj = {"title" : "2 Purple", "author" : "purple-tester1"}
Here is a sample document from the 'users' collection:
{
"_id" : ObjectId("581114330de9ac0c1445cdd6"),
"user" : "test-username1",
"likedQuizzes" : [
{
"quiz" : {
"title" : "2 Purple",
"author" : "purple-tester1"
},
"date" : ISODate("2016-10-26T20:39:02.695Z")
},
{
"quiz" : {
"title" : "1 Purple",
"author" : "purple-tester1"
},
"date" : ISODate("2016-10-26T20:39:12.374Z")
},
{
"quiz" : {
"title" : "4 Green",
"author" : "green-tester1"
},
"date" : ISODate("2016-10-26T20:39:25.304Z")
},
{
"quiz" : {
"title" : "3 Green",
"author" : "green-tester1"
},
"date" : ISODate("2016-10-26T20:39:37.326Z")
},
{
"quiz" : {
"title" : "2 Green",
"author" : "green-tester1"
},
"date" : ISODate("2016-10-26T20:40:12.964Z")
}
]
}
Said another way, I am simply trying to find if a quiz is in a users' "likedQuizzes" array, and if it is, delete it from that array (along with the "date" that it was liked).
After some researching it looks like this might not be possible, but I wanted to ask anyway because I think my schema might be different enough from the examples that came up in my research. Thanks in advance for any pointers.
You could restructure your document to be of this structure:
{
"_id" : ObjectId("581114330de9ac0c1445cdd6"),
"user" : "test-username1",
"likedQuizzes" : [
{
"title" : "2 Purple",
"author" : "purple-tester1",
"date" : ISODate("2016-10-26T20:39:02.695Z")
},
{
"title" : "1 Purple",
"author" : "purple-tester1",
"date" : ISODate("2016-10-26T20:39:12.374Z")
},
{
"title" : "4 Green",
"author" : "green-tester1",
"date" : ISODate("2016-10-26T20:39:25.304Z")
},
{
"title" : "3 Green",
"author" : "green-tester1",
"date" : ISODate("2016-10-26T20:39:37.326Z")
},
{
"title" : "2 Green",
"author" : "green-tester1",
"date" : ISODate("2016-10-26T20:40:12.964Z")
}
]
}
After that... if you run the following command:
db.users.update(
{
"likedQuizzes": {
$elemMatch: {
"title" : "2 Purple",
"author" : "purple-tester1"
}
}
},
{
$pull: {
"likedQuizzes": {
"title": "2 Purple",
"author": "purple-tester1"
}
}
}
);
Your $pull will now work. $pull doesn't seem to play nicely with $elemMatch
Well, what you are trying to do is to pass the whole quiz object to the $elemMatch and expecting it to return the match documents from MongoDB, but it won't work that way.
You have to modify your query a bit like
{"likedQuizzes.quiz.title": { $elemMatch: quizObj.title}
Reason : mongodb won't do the field by field compare for you. You should have a unique identifier based on which you can query.
Even in the RDBMS world you cannot do this.
What you are trying to do is something like:
quizObj q;
q.title = "2 Purple";
q.author = "purple-tester1";
select * from quizTable where row = q.
You can give it a try
db.users.update({"likedQuizzes": { $elemMatch: {"quiz.title" : "2 Purple", "quiz.author" : "purple-tester1"}}},
{$pull: {"likedQuizzes": {"quiz" : {"title" : "2 Purple", "author" : "purple-tester1"}}}})
What you can do is use your quizObj = {"quiz.title" : "2 Purple", "quiz.author" : "purple-tester1"}
Hope it helps.
And then below query
db.users.update({"likedQuizzes": { $elemMatch: quizObj }},{$pull: {"likedQuizzes": quizObj }})

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

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

how to use aggregation of mongodb

From the data as given below, I want to sum all Values fields.
Please let me know how can I do it using aggregation functionality of mongodb.
{"MetricRecord":
{ "SchemaVersion" : "0.12",
"Product": {
"ProductName" : "abc",
"ProductVersion": "7.5.0.1" ,
"ProductId" : "1234567890ABDFGH12345",
"InstanceId" : "12345BA32",
"InstanceName" : "1234SS123",
"SystemId" : "somehost.com"
},
"Tenant" : {
"CustomerId" : "222-555-124",
"ServiceCode": "xyzxyzxyz12345yyy"
},
"Metrics" : [
{
"ReportType" :[
{ "report" : "billing" },
],
"LogTime" : "2013-12-08T12:34:56:01Z" ,
"Type" : "AuthorizedUsers",
"SubType" : "registered",
"Value" : "125",
"UnitOfMeasure": "USD",
"Period" : {
"StartTime" : "2013-12-07T00:00:00:01Z",
"EndTime" : "2013-12-08T00:00:00:01Z"
}
},
{
"ReportType" :[
{ "report" : "billing" }
],
"LogTime" : "2013-12-08T12:34:56:01Z" ,
"Type" : "NumberOfTickets",
"SubType" : "resolved",
"Value" : "430",
"UnitOfMeasure": "USD",
"Period" : {
"StartTime" : "2013-12-07T00:00:00:01Z",
"EndTime" : "2013-12-08T00:00:00:01Z"
}
}
]
}
}
So, results which I expect from summation of values is 430+125 i.e. 555
Your document contains string value for MetricRecord.Metrics[index].Value field and i am not sure why are you trying to sum up the string values. if it is a typo and your document contains numerical values for MetricRecord.Metrics[index].Value field then you can try the following query
db.metrics.aggregate([
{$unwind:"$MetricRecord.Metrics"},
{$group:{_id:"$_id",sum:{$sum:"$MetricRecord.Metrics.Value"}}}
])
In the above document posted, if your value field is like
MetricRecord.Metrics[0].Value is 125(not "125")
MetricRecord.Metrics[1].Value is 430(not "430")
you will get the following output
{
"result" : [
{
"_id" : ObjectId("xxxxxxxxxxxxxxxxxxxxxxxx"),
"sum" : 555
}
],
"ok" : 1
}
The above sample query is composed assuming you have the default mongodb "_id" field and you are using a metrics collection. You have to manipulate the query as per you requirements.

How do I remove the "value" in mapReduce?

I was wondering if it is possible to remove the "value" key in the map-reduce so that the final result just contains the values directly rather than being inside the "value" key. I am looking to do it with just the commands (so no Javascript variables and such)
For example, the map-reduce output is typically
[
{
"_id" : 0,
"value" : {
"name" : "Apple",
"sold" : 1234
}
},
{
"_id" : 1,
"value" : {
"name" : "Amazon",
"sold" : 5678
}
}
]
I would like it to end up as
[
{
"_id" : 0,
"name" : "Apple",
"sold" : 1234
},
{
"_id" : 1,
"name" : "Amazon",
"sold" : 5678
}
]
I am thinking it can be done with the findAndModify command but I am not exactly sure how.
It does not seems to be possible for now. There is a JIRA ticket for that reported in Mongo.