How to query: aggregate.$match -> $lookup -> where x=11 - mongodb

I have two mongo collections which are in a relation:
contacts_collecion:
{ "contact_id" : "1", "e" : "a1#a.aaa" }
{ "contact_id" : "2", "e" : "a2#a.aaa" }
{ "contact_id" : "3", "e" : "a3#a.aaa" }
...
...
contacts_groups_collection:
{ "contact_id" : "2", "group_id" : "1" }
{ "contact_id" : "3", "group_id" : "1" }
{ "contact_id" : "3", "group_id" : "2" }
...
...
So typical many-to-many relation - I have also a groups_collection. Every contact can be in multi groups.
When I query:
db.contacts.aggregate([{ "$match" : { "a" : false, "e" : /ab/ } }, { "$lookup" : { "from" : "contacts_groups", "localField" : "contact_id", "foreignField" : "contact_id", "as" : "details" } }])
I get:
1) { "contact_id" : "1", "e" : "abcd#gmail.com", "details" : [{ "contact_id" : "1", "group_id" : "1" }, { "contact_id" : "1", "group_id" : "2" }] }
2) { "contact_id" : "2", "e" : "abcdef#gmail.com", "details" : [{ "contact_id" : "2", "group_id" : "2" }, { "contact_id" : "2", "group_id" : "3" }] }
3) { "contact_id" : "3", "e" : "abcdefgh#gmail.com", "details" : [] }
But I would like get only the second row (2), so only those where "group_id" : "3".
How can I do this?
Is the way I do this 'join and where' most effective?

Related

How to filter data from multiple nested documents / multiple child documents from mongodb

Here is a sample document that I am trying on
{
"_id" : "3",
"description" : "DESCRIPTION ARTICLE AD",
"article_code" : "AD",
"purchase" : [
{
"company" : 1,
"cost" : "70.010000"
},
{
"company" : 2,
"cost" : "75.820000"
},
{
"company" : 3,
"cost" : "69.910000"
}
],
"stock" : [
{
"country" : "01",
"warehouse" : {
"code" : "01",
"units" : 5
}
},
{
"country" : "01",
"warehouse" : {
"code" : "02",
"units" : 6
}
}
]
}
My use case is we have documents containing multiple objects like stock and purchase, userInfo, lang user speaks etc etc. I am applying criteria to get userInfo where username is abc and user role is admin etc . if not matched simply ignore for that particular criteria.
I want to get below output where purchase.company =2 and stocks.warehouse.units = 6.
Sample OP1 ->
"_id" : "3",
"description" : "DESCRIPTION ARTICLE AD",
"article_code" : "AD",
"purchase" : [
{
"company" : 2,
"cost" : "75.820000"
}
],
"stock" : [
{
"country" : "01",
"warehouse" : {
"code" : "02",
"units" : 6
}
}
]
}
Sample OP2 ->
"_id" : "3",
"description" : "DESCRIPTION ARTICLE AD",
"article_code" : "AD",
"purchase" : [
{
"company" : 2,
"cost" : "75.820000"
}
],
"stock" : [
{
"country" : "01",
"warehouse" : {
"units" : 6
}
}
]
}
You can use Mongodb's aggregation framework for this.
db.testdb.aggregate([
{$match: {"purchase.company": 2 , "stock.warehouse.units" : 6}},
{ $project: {
_id: 1,
description: 1,
article_code: 1,
purchase: { $filter: {
input: "$purchase",
as: "purchase",
cond: { $eq: ["$$purchase.company", 2] } } },
stock: { $filter: {
input: "$stock",
as: "stock",
cond: { $eq: ["$$stock.warehouse.units", 6] } } }
} }
]).pretty()
If you execute the query above, the output will be:
{
"_id" : "3",
"description" : "DESCRIPTION ARTICLE AD",
"article_code" : "AD",
"purchase" : [
{
"company" : 2,
"cost" : "75.820000"
}
],
"stock" : [
{
"country" : "01",
"warehouse" : {
"code" : "02",
"units" : 6
}
}
]
}

MongoDB group and merge all sub documents into parent document

Group documents and merge the list under each group to the parent document using one of the field in the sub document as key.
Here are my documents
{ "_id" : "1", "a" : "11", "b" : "o11", "c" : "s11" }
{ "_id" : "2", "a" : "22", "b" : "o22", "c" : "s22" }
{ "_id" : "3", "a" : "11", "b" : "o12", "c" : "s12" }
{ "_id" : "4", "a" : "11", "b" : "o13", "c" : "s13" }
{ "_id" : "5", "a" : "22", "b" : "o23", "c" : "s23" }
I want to group by 'a' and and merge list of subdocuments to one document like below:
{
{a:"11", o11: { "_id" : "1", "a" : "11", "b" : "o11", "c" : "s11" }, o12: { "_id" : "3", "a" : "11", "b" : "o12", "c" : "s12" }, o13: { "_id" : "4", "a" : "11", "b" : "o13", "c" : "s13" }},
{a:"22", o22: { "_id" : "2", "a" : "22", "b" : "o22", "c" : "s22" }, o23: { "_id" : "5", "a" : "22", "b" : "o23", "c" : "s23" }
}

MongoDB query with multiple conditions

I have data with multiple documents :
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e486"),
"empId" : "1"
"type" : "WebUser",
"city" : "Pune"
}
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e487"),
"empId" : "2"
"type" : "Admin",
"city" : "Mumbai"
}
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e488"),
"empId" : "3"
"type" : "Admin",
"city" : "Pune"
}
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e489"),
"empId" : "4"
"type" : "User",
"city" : "Mumbai"
}
I want to get data according to my multiple conditions :
condition 1:- {"type" : "WebUser", "city" : "Pune"}
condition 2:- {"type" : "WebUser", "city" : "Pune"} & {"type" : "User", "city" : "Mumbai"}
I want below result when run condition 1 :
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e486"),
"empId" : "1"
"type" : "WebUser",
"city" : "Pune"
}
When I run second condition :
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e486"),
"empId" : "1"
"type" : "WebUser",
"city" : "Pune"
}
{
"_id" : ObjectId("57b68dbbc19c0bd86d62e489"),
"empId" : "4"
"type" : "User",
"city" : "Mumbai"
}
I want above result by one query,
Currently I am using below aggregate query,
db.emp.aggregate([
{ $match: { '$and': [
{"type" : "WebUser", "city" : "Pune"},
{"type" : "User", "city" : "Mumbai"}
] } },
{ $group: { _id: 1, ids: { $push: "$empId" } } }
])
Above query work for first condition & fails for other. Please help me.
For the second condition, you can use the $in operator in your query as:
db.emp.find({
"type" : { "$in": ["WebUser", "User"] },
"city" : { "$in": ["Pune", "Mumbai"] }
})
If you want to use in aggregation:
db.emp.aggregate([
{
"$match": {
"type" : { "$in": ["WebUser", "User"] },
"city" : { "$in": ["Pune", "Mumbai"] }
}
},
{ "$group": { "_id": null, "ids": { "$push": "$empId" } } }
])
or simply use the distinct() method to return an array of distinct empIds that match the above query as:
var employeeIds = db.emp.distinct("empId", {
"type" : { "$in": ["WebUser", "User"] },
"city" : { "$in": ["Pune", "Mumbai"] }
});
If you are looking for the AND operator
This example checks if a field exists AND is null
db.getCollection('TheCollection').find({
$and: [
{'the_key': { $exists: true }},
{'the_key': null}
]
})
This example checks if a field has 'value1' OR 'value2'
db.getCollection('TheCollection').find({
$or: [
{'the_key': 'value1'},
{`the_key': 'value2'}
]
})
When just checking for null, the return contains non-existing fields plus fields with value null
db.getCollection('TheCollection').find({'the_key': null})
You can use mongo db $or operator.
db.emp.find({ $or: [
{ "type": "WebUser", "city": "Pune" },
{ "type": "user", "city": "Mumbai"}
]})
You can pass conditions in the array.
For more reference see mongo docs
Display the document where in the “StudName” has value “Ajay Rathod”.
db.Student.find({name:"ajay rathod"})
{ "_id" : ObjectId("5fdd895cd2d5a20ee8cea0de"), "
Retrieve only Student Name and Grade.
db.Student.find({},{name:1,grade:1,_id:0})
{ "name" : "dhruv", "grade" : "A" }
{ "name" : "jay", "grade" : "B" }
{ "name" : "abhi", "grade" : "C" }
{ "name" : "aayush", "grade" : "A" }
{ "name" : "sukhdev", "grade" : "B" }
{ "name" : "dhruval", "grade" : "B" }
{ "name" : "ajay rathod", "grade" : "D" }

Delete portion of Sub Document Collection in Mongodb

I am trying to delete a section of sub documents from a collections..
Tried (and many others):
db.collection.remove( {'Segments': {$gte: '20150612141038' }} )
db.collection.remove( { 'Segments.$' : {$gte: '0150612141038' }} )
db.collection.deleteMany( { 'Segments.$' : {$gte: '0150612141038' }} )
db.collection.deleteOne( { 'Segments.$' : {$eq: '0150612141038' }} )
just can't figure out what I am doing wrong...
{
"_id" : ObjectId("56e32c5147e030bc0a000035"),
"Date" : "2015-06-12",
"UnitID" : "5",
"Segments" : {
"20150612141037" : {
"Parameters" : {
"647" : "0",
"649" : "16",
"653" : "0",
"655" : "0",
"656" : "0",
"658" : "98",
"664" : "447.0486",
"666" : "442.7083",
"677" : "122.8004",
}
},
"20150612141038" : {
"Parameters" : {
"658" : "96",
"664" : "451.3889",
"666" : "447.0486",
"677" : "122.7892"
}
},
"20150612141039" : {
"Parameters" : {
"658" : "44",
"664" : "442.7083",
"677" : "122.8004",
"704" : "1"
}
},
First of all I think your queries are wrong.
If you try this query to the mongoShell:
db.bios.find({'Segments': {$gte: '20150612141038'}})
you don't have anything as output because 20150612141038 is a document and not a field. Maybe you can reshape your schema to set 20150612141038 as a field and Segments as an array of documents:
{
"_id" : ObjectId("56e32c5147e030bc0a000035"),
"Date" : "2015-06-12",
"UnitID" : "5",
"Segments" : [
{
"segmentId" : "20150612141037",
"Parameters" : {
"647" : "0",
"649" : "16",
"653" : "0",
"655" : "0",
"656" : "0",
"658" : "98",
"664" : "447.0486",
"666" : "442.7083",
"677" : "122.8004"
}
},
{
"segmentId" : "20150612141038",
"Parameters" : {
"658" : "96",
"664" : "451.3889",
"666" : "447.0486",
"677" : "122.7892"
}
},
{
"segmentId" : "20150612141039",
"Parameters" : {
"658" : "44",
"664" : "442.7083",
"677" : "122.8004",
"704" : "1"
}
}
]
}
and then you can use $pull operator to remove documents from Segments array where the field Segments.segmentId has a certain value:
db.collection.update({},
{$pull:{Segments:{"segmentId":{$eq:"20150612141039"}}}},
{ multi: true}
)

MongoDB groupby query

I have colletions containing records like
{ "type" : "me", "tid" : "1" }
{ "type" : "me", "tid" : "1" }
{ "type" : "me", "tid" : "1" }
{ "type" : "you", "tid" : "1" }
{ "type" : "you", "tid" : "1" }
{ "type" : "me", "tid" : "2" }
{ "type" : "me", "tid" : "2"}
{ "type" : "you", "tid" : "2"}
{ "type" : "you", "tid" : "2" }
{ "type" : "you", "tid" : "2"}
I have want result like below
[
{"tid" : "1","me" : 3,"you": 2},
{"tid" : "2","me" : 2,"you": 3}
]
I have tried group and; aggregate queries doesn't get required result format.
below is the group query.
db.coll.group({
key: {tid : 1,type:1},
cond: { tid : { "$in" : [ "1","2"]} },
reduce: function (curr,result) {
result.total = result.total + 1
},
initial: { total : 0}
})
it result is like
[
{"tid" : "1", "type" : "me" ,"total": 3 },
{"tid" : "1","type" : "you" ,"total": 2 },
{"tid" : "2", "type" : "me" ,"total": 2 },
{"tid" : "2","type" : "you" ,"total": 3 }
]
following is aggregate query
db.coll.aggregate([
{$match : { "tid" : {"$in" : ["1","2"]}}},
{$group : { _id : {tid : "$tid",type : "$type"},total : {"$sum" : 1}}}
])
gives following result
{
"result" :
[
{"_id" : {"tid" : "1","type" : "me"},"total" : 3},
{"_id" : {"tid" : "2","type" : "me" },"total" : 2},
{"_id" : {"tid" : "2","type" : "you"},"total" : 3}
]
"ok" : 1
}
it is possible to obtain I specified result or I have to do some manipulation in my code.
Thanks
If you change your aggregation to this:
db.so.aggregate([
{ $match : { "tid" : { "$in" : ["1", "2"] } } },
{ $group : {
_id : { tid : "$tid", type : "$type" },
total : { "$sum" : 1 }
} },
{ $group : {
_id : "$_id.tid",
values: { $push: { type: "$_id.type", total: '$total' } }
} }
])
Then your output is:
{
"result" : [
{
"_id" : "1",
"values" : [
{ "type" : "you", "total" : 2 },
{ "type" : "me", "total" : 3 }
]
},
{
"_id" : "2",
"values" : [
{ "type" : "me", "total" : 2 },
{ "type" : "you", "total" : 3 }
]
}
],
"ok" : 1
}
Although that is not the same as what you want, it is going to be the closest that you can get. And in your application, you can easily pull out the values in the same was as with what you would like to get out of it.
Just keep in mind, that in general you can not promote a value (you, me) to a key — unless your key is of a limited set (3-4 items max).