OrderBy in mongo db to get some thing like this - mongodb

I am very new to mongodb. Please help me get a solution for this.
The below are the documents in mongo db :
{name : sass, city : banga},
{name : pass, city : banga},
{name : kanga, city : runga},
{name : jass, city : canga},
{name : dass, city : tunga}
I want to query with city as 'banga', so that the result array should contain documents with city 'banga' first and then all other documents.
Thanks.

Please try this. The below query will give you "banga" at the top and all other documents after that.
Note:-
Please note that the query doesn't sort the data by city. It just return the "banga" documents at the top. The documents where "city" not equals to "banga" could be in any order after that.
Query:-
You may need to change the collection name accordingly in the below query.
db.collection.aggregate([
{ $project: {_id : 1, "name": 1, "city" : 1,
isRequiredCity: { $cond: { if: { $eq: [ "$city", "banga" ] }, then: 0, else: 1 } }} },
{$sort : {"isRequiredCity" : 1} }
]);
Output:-
/* 1 */
{
"_id" : ObjectId("58342ccaba41f1f22e600c67"),
"name" : "sass",
"city" : "banga",
"isRequiredCity" : 0
}
/* 2 */
{
"_id" : ObjectId("58342ccaba41f1f22e600c6a"),
"name" : "pass",
"city" : "banga",
"isRequiredCity" : 0
}
/* 3 */
{
"_id" : ObjectId("58342ccaba41f1f22e600c68"),
"name" : "kanga",
"city" : "runga",
"isRequiredCity" : 1
}
/* 4 */
{
"_id" : ObjectId("58342ccaba41f1f22e600c69"),
"name" : "jass",
"city" : "canga",
"isRequiredCity" : 1
}
/* 5 */
{
"_id" : ObjectId("58342ccaba41f1f22e600c6b"),
"name" : "dass",
"city" : "tunga",
"isRequiredCity" : 1
}

An option for that is to add a specific field to all the documents. The new field will identify by a unique value all the documents contains city : banga.
Than you can order all the collection based on that values.
For example, lets add to all the collection the unique field and a unique value:
db.collection.update({'city':'banga'}, {$set:{"value":10}}, {upsert:false, multi:true});
db.collection.update({'city': { $ne: 'banga'}}, {$set:{"value":1}}, {upsert:false, multi:true});
Now, each document with field 'city'=='banga' has value = 10, and each document with field 'city'!='banga' has value = 1.
And now you can sort the documents in the collection using the value field.
db.collection.find({}).sort({'value': -1})

Related

mongodb findOneAndUpdate only if a certain condition is met

Following is my mongo db entries.
my-mongo-set:PRIMARY> db.stat_collection.find({name : /s/})
{ "_id" : ObjectId("5aabf231a167b3808302b138"), "name" : "shankarmr", "email" : "abc#xyz", "rating" : 9901 }
{ "_id" : ObjectId("5aabf23da167b3808302b139"), "name" : "shankar", "email" : "abc1#xyz1", "rating" : 10011 }
{ "_id" : ObjectId("5aabf2b5a167b3808302b13a"), "name" : "shankar1", "email" : "abc2#xyz2", "rating" : 10 }
{ "_id" : ObjectId("5aabf2c2a167b3808302b13b"), "name" : "shankar2", "email" : "abc3#xyz3", "rating" : 100 }
Now i want to find an entry based on name but update a field only if a certain condition holds good.
I tried the following statement, but it gives me error at the second reference to $rating.
db.stat_collection.findOneAndUpdate({name: "shankar"}, {$set : {rating : {$cond : [ {$lt : [ "$rating", 100]}, 100, $rating]}}, $setOnInsert: fullObject}, {upsert : true} )
So in my case, it shouldnot update rating for the 2nd document as the rating is not less than 100. But for the third document, rating should be updated to 100.
How do i get it work?
$max is the operator you're looking for, try:
db.stat_collection.findOneAndUpdate( { name: "shankar1"}, { $max: { rating: 100 } }, { returnNewDocument: true } )
You'll either get old value (if is greater than 100) or modify a document and set 100
According to the documentation:
The $max operator updates the value of the field to a specified value if the specified value is greater than the current value of the field. The $max operator can compare values of different types, using the BSON comparison order.
You should put all conditions in the query part of the update:
db.stat_collections.findOneAndUpdate(
{ name: "Shankar", rating: { $lt: 100 } },
$set : { rating: 100 },
);
"If the name is Shankar and rating is less than 100, then set the rating to 100." is the above.

Why does MongoDB sort return empty names for ascending sorted documents?

I have a simple collection of restaurants (from MongoDB documentation). One of the fields is “name”. I can easily find all the names of the restaurants as follows:
db.restaurants.find({}, {"name" : 1, "_id" : 0});
If I try to sort by descending order, i.e.,
db.restaurants.find({}, {"name" : 1, "_id" : 0}).sort({"name":-1});
everything comes out fine:
{ "name" : "Zz'S Pizza & Grill" }
{ "name" : "Zz Clam Bar" }
...
However, if I try to sort by ascending order:
db.restaurants.find({}, {"name" : 1, "_id" : 0}).sort({"name":1});
I get
{ "name" : "" }
{ "name" : "" }
...
What's odd is that if I add other keys to the sort argument before "name", it then does the ascending sort properly, i.e.
db.restaurants.find({}, {"name" : 1, "_id" : 0}).sort({"cuisine":1, "name":1});
What gives? Thanks for any insights!

I need to count how many children orgs are assigned to a parent org in MongoDB

I'm new to the MongoDB world. I'm trying to figure out how to count the number of children organizations assigned to a parent organization. I have documents that have this general structure:
{
"_id" : "001",
"parentOrganization" : {
"organizationId" : "pOrg1"
},
"childOrganization" : {
"organizationId" : "cOrg1"
}
},
{
"_id" : "002",
"parentOrganization" : {
"organizationId" : "pOrg1"
},
"childOrganization" : {
"organizationId" : "cOrg2"
}
},
{
"_id" : "003",
"parentOrganization" : {
"organizationId" : "pOrg2"
},
"childOrganization" : {
"organizationId" : "cOrg3"
}
}
Each document has a parentOrganization with an associated childOrganization. There may be multiple documents with the same parentOrganization, but different childOrganizations. There may also be multiple documents with the same parent/child relationship. Additionally, there may even be a case where a child org may associate with multiple parent orgs.
I'm trying to group by parentOrganization and then count the number of unique childOrganization's associated with each parentOrganization, as well as display the unique id's.
I have tried using an aggregation framework with $match and $group, but I'm still not getting into the child organization parts to count them. Here is what I'm currently attempting:
var s1 = {$match: {"parentOrganization.organizationId": {$exists: true}}};
var s2 = {$group: {_id: "$parentOrganization.organizationId", count: {$sum: "$childOrganization.organizationId"}}};
db.collection.aggregate(s1, s2);
My results are returning the parentOrganization, but my $sum is not returning the number of associated childOrganizations:
/* 1 */
{
"_id" : "pOrg1",
"count" : 0
}
/* 2 */
{
"_id" : "pOrg2",
"count" : 0
}
I get the feeling it is a bit more complicated than my limited knowledge has access to at this time. What details am I missing in this query?
Your $sum is referencing the childOrganization.organizationId value, which is a string. When $sum references a string, it will return the value 0.
I was a unsure of exactly what you were asking for, but I believe that these aggregations can help you on your way.
This will return a count of documents groups by the parentOrganization.organizationId
db.collection.aggregate({$group: {"_id":"$parentOrganization.organizationId", "count": {"$sum": 1}}})
Output:
{ "_id" : "pOrg2", "count" : 1 }
{ "_id" : "pOrg1", "count" : 2 }
This will return a count of unique parent/child organizations:
db.collection.aggregate(
{$group: {"_id": {"parentOrganization": "$parentOrganization.organizationId", "childOrganization": "$childOrganization.organizationId"}, "count":{$sum:1}}})
Output:
{ "_id" : { "parentOrganization" : "pOrg2", "childOrganization" : "cOrg3" }, "count" : 1 }
{ "_id" : { "parentOrganization" : "pOrg1", "childOrganization" : "cOrg2" }, "count" : 1 }
{ "_id" : { "parentOrganization" : "pOrg1", "childOrganization" : "cOrg1" }, "count" : 1 }
This will return a count of unique child organizations and get the set of unique child organizations as well using $addToSet. One caveat of using $addToSet is that the MongoDB 16MB limit on document size still holds. This means that if your collection is large enough such that the size of the set will make one document greater than 16MB, the command will fail. The first $group will create a set of child organizations grouped by parent organization. The $project is used simply to add the total size of the set to the result.
db.collection.aggregate([
{$group: {"_id" : "$parentOrganization.organizationId", "childOrgs" : { "$addToSet" : "$childOrganization.organizationId"}}},
{$project: {"_id" : "$_id", "uniqueChildOrgsCount": {"$size" : "$childOrgs"}, "uniqueChildOrgs": "$childOrgs"}}])
Output:
{ "_id" : "pOrg2", "uniqueChildOrgsCount" : 1, "uniqueChildOrgs" : [ "cOrg3" ]}
{ "_id" : "pOrg1", "uniqueChildOrgsCount" : 2, "uniqueChildOrgs" : [ "cOrg2", "cOrg1" ]}
During these aggregations, I left out the $match statement you included for simplicity, but you could add that back as well.

mongodb get elements which was inserted after some document

I have a document and I need to query mongodb database to return me all the documents which was inserted after current document.
Is it possible and how to do that query?
If you do not override the default _id field you can use that objectID (see the mongodb docs) to make a comparison by time. For instance, the following query will find all the documents that are inserted after curDoc has been inserted (assuming none overwrite the _id field):
>db.test.find({ _id : {$gt : curDoc._id}})
Note that these timestamps are not super granular, if you would like a finer grained view of the time that documents are inserted I encourage you to add your own timestamp field to the documents you are inserting and use that field to make such queries.
If you are using Insert time stamp as on of the parameter, you can query like below
> db.foo.find()
{ "_id" : ObjectId("514bf8bbbe11e483111af213"), "Name" : "abc", "Insert_time" : ISODate("2013-03-22T06:22:51.422Z") }
{ "_id" : ObjectId("514bf8c5be11e483111af214"), "Name" : "xyz", "Insert_time" : ISODate("2013-03-22T06:23:01.310Z") }
{ "_id" : ObjectId("514bf8cebe11e483111af215"), "Name" : "pqr", "Insert_time" : ISODate("2013-03-22T06:23:10.006Z") }
{ "_id" : ObjectId("514bf8eabe11e483111af216"), "Name" : "ijk", "Insert_time" : ISODate("2013-03-22T06:23:38.410Z") }
>
Here my Insert_time corresponds to the document inserted time, and following query will give you the documents after a particular Insert_time,
> db.foo.find({Insert_time:{$gt:ISODate("2013-03-22T06:22:51.422Z")}})
{ "_id" : ObjectId("514bf8c5be11e483111af214"), "Name" : "xyz", "Insert_time" : ISODate("2013-03-22T06:23:01.310Z") }
{ "_id" : ObjectId("514bf8cebe11e483111af215"), "Name" : "pqr", "Insert_time" : ISODate("2013-03-22T06:23:10.006Z") }
{ "_id" : ObjectId("514bf8eabe11e483111af216"), "Name" : "ijk", "Insert_time" : ISODate("2013-03-22T06:23:38.410Z") }
>

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.