Getting the correct query in Mongodb - mongodb

I'm trying to get this simple query to just get a subfield out of a collection. So far I just keep getting the entire field so what should I correct to just print out the subfield I'm looking for?
I'm trying to list the titles (only) of all movies with a rank of less than 9.2 and with at least 5 votes, print the titles in alphabetical order.
This is my query so far but its incorrect and just returns the whole object. How can I get it to return just the rank and votes of Jungle Book? Thank you very much in advance.
db.collections.find({"title": {$exists:true}}, {"_id":0, "rank":{$lt : 9.2}})
{ "_id" : ObjectId("10"), "rank" : 6, "votes" : 8.8, "title" : "Jungle Book" }
{ "_id" : ObjectId("11"), "rank" : 8, "votes" : 8.7, "title" : "Spawn" }

You need to have the filter/query all in the first parameter. The second parameter is a set of booleans for which properties it should return.
db.ratings.find({title: {$exists:true}, rank:{$lt : 9.2},
votes: {$gte : 5 } }, {_id:0, title:1}).sort({title:1})
This will return a set that looks like this:
[{"title" : "Jungle Book"}, {"title" : "Spawn"}]
If you want only the titles, and not in object form you could use "distinct" here:
db.ratings.distinct('title', {title: {$exists:true},
rank:{$lt : 9.2}, votes: {$gte : 5 } });
The distinct query should be sorted by default. If you want to sort it a different way you'll need to use an aggregate query.
I've run this EXACT set of code against my local install:
MongoDB shell version: 2.4.8
connecting to: test
rs0:PRIMARY> db.ratings.insert({rank:6, votes:8.8, title:"Jungle Book"});
rs0:PRIMARY> db.ratings.insert({rank:8, votes:8.7, title:"Spawn"});
rs0:PRIMARY> db.ratings.find({title: {$exists:true}, rank:{$lt : 9.2}, votes: {$gte : 5 } }, {_id:0, title:1}).sort({title:1})
{ "title" : "Jungle Book" }
{ "title" : "Spawn" }
rs0:PRIMARY> db.ratings.distinct('title', {title: {$exists:true}, rank:{$lt : 9.2}, votes: {$gte : 5 } });
[ "Jungle Book", "Spawn" ]
rs0:PRIMARY>

Related

MongoDB get all embedded documents where condition is met

I did this in my mongodb:
db.teams.insert({name:"Alpha team",employees:[{name:"john"},{name:"david"}]});
db.teams.insert({name:"True team",employees:[{name:"oliver"},{name:"sam"}]});
db.teams.insert({name:"Blue team",employees:[{name:"jane"},{name:"raji"}]});
db.teams.find({"employees.name":/.*o.*/});
But what I got was:
{ "_id" : ObjectId("5ddf3ca83c182cc5354a15dd"), "name" : "Alpha team", "employees" : [ { "name" : "john" }, { "name" : "david" } ] }
{ "_id" : ObjectId("5ddf3ca93c182cc5354a15de"), "name" : "True team", "employees" : [ { "name" : "oliver" }, { "name" : "sam" } ] }
But what I really want is
[{"name":"john"},{"name":"oliver"}]
I'm having a hard time finding examples of this without using some kind of programmatic iterator/loop. Or examples I find return the parent document, which means I'd have to parse out the embedded array employees and do some kind of UNION statement?
Eg.
How to get embedded document in mongodb?
Retrieve only the queried element in an object array in MongoDB collection
Can someone point me in the right direction?
Please add projections to filter out the fields you don't need. Please refer the project link mongodb projections
Your find query should be constructed with the projection parameters like below:
db.teams.find({"employees.name":/.*o.*/}, {_id:0, "employees.name": 1});
This will return you:
[{"name":"john"},{"name":"oliver"}]
Can be solved with a simple aggregation pipeline.
db.teams.aggregate([
{$unwind : "$employees"},
{$match : {"employees.name":/.*o.*/}},
])
EDIT:
OP Wants to skip the parent fields. Modified query:
db.teams.aggregate([
{$unwind : "$employees"},
{$match : {"employees.name":/.*o.*/}},
{$project : {"name":"$employees.name",_id:0}}
])
Output:
{ "name" : "john" }
{ "name" : "oliver" }

Updating nested List in mongoDB Query working sometimes but with large data set it fails [duplicate]

This question already has answers here:
Updating a Nested Array with MongoDB
(2 answers)
Closed 5 years ago.
Following is a MongoDB document:
{
"_id" : 2,
"mem_id" : M002,
"email" : "xyz#gmail.com",
"event_type" : [
{
"name" : "MT",
"count" : 1,
"language" : [
{
"name" : "English",
"count" : 1,
"genre" : [
{
"name" : "Action",
"count" : 6
},
{
"name" : "Sci-Fi",
"count" : 3
}
],
"cast" : [
{
"name" : "Sam Wortington",
"count" : 2
},
{
"name" : "Bruce Willis",
"count" : 4
},
{
"name" : "Will Smith",
"count" : 7
},
{
"name" : "Irfan Khan",
"count" : 1
}
]
}
]
}
]
}
I'm not able to update fields that is of type array, specially event_type, language, genre and cast because of nesting. Basically, I wanted to update all the four mentioned fields along with count field for each and subdocuments. The update statement should insert a value to the tree if the value is new else should increment the count for that value.
What can be the query in mongo shell?
Thanks
You are directly hitting one of the current limitations of MongoDB.
The problem is that the engine does not support several positional operators.
See this Multiple use of the positional `$` operator to update nested arrays
There is an open ticket for this: https://jira.mongodb.org/browse/SERVER-831 (mentioned also there)
You can also read this one on how to change your data model: Updating nested arrays in mongodb
If it is feasible for you, you can do:
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.0.language.$.count":<number>}})
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.$.language.0.count":<number>}})
But you cannot do:
db.collection.update({_id:2,"event_type.name":'MT' ,"event_type.language.name":'English'},{$set:{"event_type.$.language.$.count":<number>}})
Let's take case by case:
To update the field name in event_type array:
db.testnested.update({"event_type.name" : "MT"}, {$set : {"event_type.name" : "GMT"}})
This command will update the name for an object inside the event_type list, to GMT from MT:
BEFORE:
db.testnested.find({}, {"event_type.name" : 1})
{ "_id" : 2, "event_type" : [ { "name" : "MT" } ] }
AFTER:
db.testnested.find({}, {"event_type.name" : 1})
{ "_id" : 2, "event_type" : [ { "name" : "GMT" } ] }
2.To update fields inside event_type, such as language, genre that are intern list:
There is no direct query for this. You need to read the document, update that document using the JavaScript or language of your choice, and then save() the same. I dont think there is any other way available till mongo 2.4
For further documentation, you can refer to save().
Thanks!

How sum in MongoDB nested document when the KEY is uncertain ?

First of all the status codes("200","404" or other) and time("1000","2000"..) are uncertain,
I want to calculate the number(5, 6 ...) for each status codes.
For example: {"200" : 11}, {"404" :11} or {"total" : 22}
Data Structure :
"_id" : "xxxxx"
"domain" : "www.test.com"
"status" : [
{"200" : [ {"1000" : 5}, {"2000": 6} ...]},
{"404" : [ {"1000" : 5}, {"2000": 6} ...]}
....
]
Any fantastic methods in MongoDB ?
Thank you for your help
Don't use data, like dates, as keys. Data belongs in values. The HTTP status codes are enumerated - you know all the possibilities - so you can use those as keys if you want to. From the look of the documents, you are storing information about requests to a page in a page document with the requests in an array. It's not a great idea to have an unbounded, constantly growing array in a document. I'd suggest refactoring the data to be request documents with the address denormalized into each:
{
"_id" : ObjectId(...),
"status" : 404,
"date" : ISODate("2014-10-30T18:23:09.471Z"),
"domain" : "www.test.com"
}
and then you can get the total number of 404 requests to test.com with the aggregation
db.requests.aggregate([
{ "$match" : { "domain" : "www.test.com" } },
{ "$group" : { "_id" : "$status", "count" : { "$sum" : 1 } } }
])
Index on domain to make it fast.
I think you can use the aggregation framework to pull something like that.
Check this:
db.errors.aggregate([{$unwind: "$status"}, {$group: {_id: "$status", total:{$sum:1}}}])
It will render a result like this:
...
"result" : [
{
"_id" : {
"500" : [
{
"1000" : 5
},
{
"2000" : 6
}
]
},
"total" : 1
},
...
The "total" field has the count that you're looking for.
Hope this helps.
Regards!

MongoDb - How to search BSON composite key exactly?

I have a collection that stored information about devices like the following:
/* 1 */
{
"_id" : {
"startDate" : "2012-12-20",
"endDate" : "2012-12-30",
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount"]
},
"data" : {
"results" : "1"
}
}
/* 2 */
{
"_id" : {
"startDate" : "2012-12-20",
"endDate" : "2012-12-30",
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
},
"data" : {
"results" : "2"
}
}
/* 3 */
{
"_id" : {
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
},
"data" : {
"results" : "3"
}
}
And I am trying to query the documents using the _id field which will be unique. The problem I am having is that when I query for all the different attributes as in:
db.collection.find({$and: [{"_id.dimensions":{ $all: ["manufacturer","model"], $size: 2}}, {"_id.metrics": { $all:["noOfUsers","deviceCount"], $size: 2}}]});
This matches 2 and 3 documents (I don't care about the order of the attributes values), but I would like to only get 3 back. How can I say that there should not be any other attributes to _id than those that I specify in the search query?
Please advise. Thanks.
Unfortunately, I think the closest you can get to narrowing your query results to just unordered _id.dimensions and unordered _id.metrics requires you to know the other possible fields in the _id subdocument field, eg. startDate and endDate.
db.collection.find({$and: [
{"_id.dimensions":{ $all: ["manufacturer","model"], $size: 2}},
{"_id.metrics": { $all:["noOfUsers","deviceCount"], $size: 2}},
{"_id.startDate":{$exists:false}},
{"_id.endDate":{$exists:false}}
]});
If you don't know the set of possible fields in _id, then the other possible solution would be to specify the exact _id that you want, eg.
db.collection.find({"_id" : {
"dimensions" : ["manufacturer", "model"],
"metrics" : ["deviceCount", "noOfUsers"]
}})
but this means that the order of _id.dimensions and _id.metrics is significant. This last query does a document match on exact BSON representation of _id.

Map reduce in mongodb

I have mongo documents in this format.
{"_id" : 1,"Summary" : {...},"Examples" : [{"_id" : 353,"CategoryId" : 4},{"_id" : 239,"CategoryId" : 28}, ... ]}
{"_id" : 2,"Summary" : {...},"Examples" : [{"_id" : 312,"CategoryId" : 2},{"_id" : 121,"CategoryId" : 12}, ... ]}
How can I map/reduce them to get a hash like:
{ [ result[categoryId] : count_of_examples , .....] }
I.e. count of examples of each category.
I have 30 categories at all, all specified in Categories collection.
If you can use 2.1 (dev version of upcoming release 2.2) then you can use Aggregation Framework and it would look something like this:
db.collection.aggregate( [
{$project:{"CatId":"$Examples.CategoryId","_id":0}},
{$unwind:"$CatId"},
{$group:{_id:"$CatId","num":{$sum:1} } },
{$project:{CategoryId:"$_id",NumberOfExamples:"$num",_id:0 }}
] );
The first step projects the subfield of Examples (CategoryId) into a top level field of a document (not necessary but helps with readability), then we unwind the array of examples which creates a separate document for each array value of CatId, we do a "group by" and count them (I assume each instance of CategoryId is one example, right?) and last we use projection again to relabel the fields and make the result look like this:
"result" : [
{
"CategoryId" : 12,
"NumberOfExamples" : 1
},
{
"CategoryId" : 2,
"NumberOfExamples" : 1
},
{
"CategoryId" : 28,
"NumberOfExamples" : 1
},
{
"CategoryId" : 4,
"NumberOfExamples" : 1
}
],
"ok" : 1