aggregation query for mongodb which uses lookup, match - mongodb

I tried to write a query in which collection 1 (User) consists of username,reporting manager,empId and collection two (quotation collection) The result i want is if logged in person is manager need to display the quotations created by there team and quotation created by themselves
User.aggregate([
{ $match: { reportingManager: req.user.user.name } },
{
$lookup:
{
from: 'Quotation',
localField: 'empId',
foreignField: 'salesCrm',
as: 'data'
}
},
{ $unwind: "$data" },
{$match:{"data.salesCrm":{$in:[req.user.user.empId]}}}
]
My user collection
{
"_id" : ObjectId("5b569cb4e924600e208660d6"),
"name" : "abc",
"email" : "abc#knowledgew.com",
"designation" : "Software Developer",
"department" : "Software Developer",
"empId" : "123",
"mobileNo" : 24564121654.0,
"password" : "$2a$10$5d/0XV.yq.w5.Ipwc2uvtuvK4Mxji0f1mUW8rBwlhu/QR8jpztoOu",
"vertical" : "Education,Market Research,Manufacturing,IT/ITES,BFSI",
"reportingManager" : "def",
"level" : "L1"
}
My quotation Collection
{
"_id" : ObjectId("5b4f27f476d65f25cc8d80ba"),
"clientId" : "VPKW00001",
"clientName" : "sssssss",
"quotationId" : "00001_1819_CG7JE",
"pmCost" : NumberInt(34),
"contactPerson" : "5b4310db728ebf030c447ebd",
"fileDomain" : "Panel Interview",
"clientDomain" : "Software",
"fuzzyMatch" : "No",
"fileEngineering" : NumberInt(34),
"workingDays" : "34",
"currency" : "GBP",
"scopeOfWork" : "LZ6PKLY_prod2.png",
"projectPlan" : "V1RK7BW_prod2.png",
"projectType" : "nnnn",
"projectValue" : 646.41,
"salesCrm" : "123",
}

Related

Mongodb match with multiple condition not working

I have user collection having data like this
{
"_id" : ObjectId("5da594c15324fec81d000027"),
"password" : "******",
"activation" : "Active",
"userType" : "Author",
"email" : "something#gmail.com",
"name" : "Something",
"profilePicture" : "profile_pictures/5da594c15324fec81d0000271607094354423image.png",
"__v" : 0
}
On the other hand userlog has data like this
{
"_id" : ObjectId("5fcb7bb4485c34a41900002b"),
"duration" : 2.54,
"page" : 1,
"activityDetails" : "Viewed Page for seconds",
"contentType" : "article",
"activityType" : "articlePageStayTime",
"bookId" : ObjectId("5f93e2cc74153f8c1800003f"),
"ipAddress" : "::1",
"creator" : ObjectId("5da594c15324fec81d000027"),
"created" : ISODate("2020-12-05T12:23:16.867Z"),
"__v" : 0
}
What I need is data like below
{
"_id" : ObjectId("5da594c15324fec81d000027"),
"password" : "******",
"activation" : "Active",
"userType" : "Author",
"email" : "something#gmail.com",
"name" : "Something",
"profilePicture" : "profile_pictures/5da594c15324fec81d0000271607094354423image.png",
"userlogs":
[{
"_id" : ObjectId("5fcb7bb4485c34a41900002b"),
"duration" : 2.54,
"page" : 1,
"activityDetails" : "Viewed Page for seconds",
"contentType" : "article",
"activityType" : "articlePageStayTime",
"bookId" : ObjectId("5f93e2cc74153f8c1800003f"),
"ipAddress" : "::1",
"creator" : ObjectId("5da594c15324fec81d000027"),
"created" : ISODate("2020-12-05T12:23:16.867Z"),
"__v" : 0
}]
}
I am trying to find all the user except admin with their log for each month. So my condition is user wont be admin and date will be between two range. But it is not working. My current code is below which is returning empty dataset-
User
.aggregate([
{
$match: {
userType: {
$ne:"admin"
}
},
"$and": [
{
"userlogs.created": {
$lte: dateCompare.end
}
},
{
"userlogs.created": {
$gte: dateCompare.start
}
}
]
},
{
$lookup:{
from: "userlogs", //or Races.collection.name
localField: "_id",
foreignField: "creator",
as: "userlogs"
},
},
]
I am using mongodb version 3.2
Try this
User.aggregate([
{
$match: {
userType: {
$ne:"admin"
}
},
{
$graphLookup:{
from: "userlogs", //or Races.collection.name
startWith: "$_id",
connectToField:"creator",
connectFromField:"_id",
maxDepth:0,
as: "userlogs",
restrictSearchWithMatch:{created:{
$lte:dateCompare.end,
$gte:dateCompare.start
}}
},
} ]

How to collect string fields from lookup documents into an array field of root documents in MongoDb [duplicate]

For MongoDB, when using $lookup to query more than one collection, is it possible to get a values-only list for a field returned in the $lookup?
What I don't want is a list of the full object with all its key/values.
Data:
failover_tool:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo"
}
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo"
}
failover_tool:PRIMARY> db.bar.find().pretty()
{
"_id" : ObjectId("5ce72e0c5267960532b8df06"),
"name" : "bar1",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e165267960532b8df07"),
"name" : "bar2",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e1d5267960532b8df08"),
"name" : "bar3",
"foo" : "foo2"
}
Desired Query Output
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : ["bar1", "bar2"]
},
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : ["bar3"]
}
Closest
This query seems like it's almost there, but it returns too much data in the bars field:
db.foo.aggregate({
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
}).pretty()
Just use .dot notation with the name field
db.foo.aggregate([
{ "$lookup": {
"from": "bar",
"localField": "name",
"foreignField": "foo",
"as": "bars"
}},
{ "$addFields": { "bars": "$bars.name" }}
])
MongoPlayground
Hope below query helps :
db.foo.aggregate([{
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
},
{$unwind : '$bars'},
{
$group : {
_id : {
_id : '$_id',
name : '$name',
desc : '$desc'
},
bars : { $push : '$bars.name'}
}
},
{
$project : {
_id : '$_id._id',
name : '$_id.name',
desc : '$_id.desc',
bars : '$bars'
}
}
]).pretty()
output :
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : [
"bar3"
]
}
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : [
"bar1",
"bar2"
]
}

How to display name with the id but with datas in 2 collections MongoDb?

I just want change a Id by thea name corresponding. But id is in a collection and name in other collection. "$lookup" Mongo doesn't work in my case...
The first collection "parameter" contains items with the "category_id":
{"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"data" : {
"capacity" : NumberInt(60),
"categories" : [
{
"category_id" : "5964961294ff4a37988e8f9b",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
{
"category_id" : "596495c994ff4a37988e8f99",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
],
},
"type" : "launcher",
"name" : "launcherp01",
"description" : "",
"_class" : "parameter"
}
....
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"data" : {
"capacity" : NumberInt(60),
"categories" : [
{
"category_id" : "596495c994ff4a37988e8f99",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
{
"category_id" : "8864961294ff4a37988e8f3b",
"nbMax" : NumberInt(1),
"nbRes" : NumberInt(0)
},
],
},
"type" : "launcher",
"name" : "launcherp01",
"description" : "",
"_class" : "parameter"
}
.....
The second Collection "reference" contains the description of categories with the _id (same as category_id in first collection) and the name:
{
"_id" : ObjectId("596495c994ff4a37988e8f99"),
"taskType" : "qc",
"type" : "category",
"name" : "**qcSupportNormal01**",
"_class" : "reference",
}
{
"_id" : ObjectId("5964961294ff4a37988e8f9b"),
"taskType" : "transcode",
"type" : "category",
"name" : "tsSupportNormal01",
"_class" : "reference",
}
I want something like that (item with categories names not id):
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"qcSupportNormal01", //--->> name from reference collection
"tsSupportNormal01", //--->> name from reference collection
}
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [
"qcSupportNormal01", //--->> name from reference collection
"qptestNormal01", //--->> name from reference collection
...
My query:
db.parameters.aggregate([
///////////////////////item filter
{$match: {
type:{ $in: [ "launcher" ] } ,
}},
///////////////////// foreign field
{$lookup: {
from: "references",
localField: "categories",
foreignField: "_id",
as: "references"
}},
/////////////////// projection
{$project:
{_id:1,type:1,categories:"$data.categories.category_id"
}},
])
but the result is always with id not the name:
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"5964961294ff4a37988e8f9b", //--->> id not name from reference collection !
"596495c994ff4a37988e8f99", //--->> id not name from reference collection !
...
How to have the category name not the id.
Very simple in Sql (joint with foreign key and reference table) but complex in Mongo query ...
Thanks for your help
je déteste le langage Mongo !
There are a couple of issues with your approach:
You are trying to call $lookup between an ObjectId and a string value.
For your categories field you are mapping it with the category_id from the data.categories whereas it should have come from references.name.
The field category_id is nested inside of an array and when you are calling the $lookup you are matching it with the whole array instead of the key field.
So, now the best approach would be to convert the field category_id to an ObjectId and then call the $lookup for the field(instead of modifying the actual field i have appended a new field named as cat_id).
Here is how i would do it:
db.parameter.aggregate([
{
$match: {
type: { $in: ["launcher"] },
}
},
{ $unwind: "$data.categories" },
{ $addFields: { "data.categories.cat_id": { $convert: { input: "$data.categories.category_id", to: "objectId" } } } },
{
$lookup: {
from: "references",
localField: "data.categories.cat_id",
foreignField: "_id",
as: "ref"
}
},
{
$project:
{
_id: 1, type: 1, categories: "$ref.name"
}
}
]);
Which will give you an output as:
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"tsSupportNormal01"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4569"),
"type" : "launcher",
"categories" : [
"**qcSupportNormal01**"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [
"**qcSupportNormal01**"
]
},
{
"_id" : ObjectId("56cc8827b9e4ed0fd42a4847"),
"type" : "launcher",
"categories" : [ ]
}

Get values as array of elements after $lookup

For MongoDB, when using $lookup to query more than one collection, is it possible to get a values-only list for a field returned in the $lookup?
What I don't want is a list of the full object with all its key/values.
Data:
failover_tool:PRIMARY> db.foo.find().pretty()
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo"
}
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo"
}
failover_tool:PRIMARY> db.bar.find().pretty()
{
"_id" : ObjectId("5ce72e0c5267960532b8df06"),
"name" : "bar1",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e165267960532b8df07"),
"name" : "bar2",
"foo" : "foo1"
}
{
"_id" : ObjectId("5ce72e1d5267960532b8df08"),
"name" : "bar3",
"foo" : "foo2"
}
Desired Query Output
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : ["bar1", "bar2"]
},
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : ["bar3"]
}
Closest
This query seems like it's almost there, but it returns too much data in the bars field:
db.foo.aggregate({
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
}).pretty()
Just use .dot notation with the name field
db.foo.aggregate([
{ "$lookup": {
"from": "bar",
"localField": "name",
"foreignField": "foo",
"as": "bars"
}},
{ "$addFields": { "bars": "$bars.name" }}
])
MongoPlayground
Hope below query helps :
db.foo.aggregate([{
$lookup: {
from:"bar",
localField:"name",
foreignField: "foo",
as:"bars"
}
},
{$unwind : '$bars'},
{
$group : {
_id : {
_id : '$_id',
name : '$name',
desc : '$desc'
},
bars : { $push : '$bars.name'}
}
},
{
$project : {
_id : '$_id._id',
name : '$_id.name',
desc : '$_id.desc',
bars : '$bars'
}
}
]).pretty()
output :
{
"_id" : ObjectId("5ce72e4a5267960532b8df0a"),
"name" : "foo2",
"desc" : "second foo",
"bars" : [
"bar3"
]
}
{
"_id" : ObjectId("5ce72e415267960532b8df09"),
"name" : "foo1",
"desc" : "first foo",
"bars" : [
"bar1",
"bar2"
]
}

$lookup and $match Mongodb golang

I want to get document with foreign key by using $lookup and $match on MongoDB.
There is a "Jobs" collection which stores Job document. In Job document there are two field using as foreing key "creatorParent" and "Children".
CreatorParent is a foreign key for "Users" collection and Children array contains id for user's children.
When I list the whole jobs, I want to retrieve detail from "Users" collection for both CreatorParent ID and ChildrenID. I want to marshall "Job" document with ParentDetail and ChildDetail. I don't want to write a custom method for that. Is it possible to handle it with MongoDB query?
By the way I'm beginner on MongoDB so should store needed details on Children and CreatorParent instead of storing ObjectId?
Users document:
{
"_id" : ObjectId("58daf84877733645eaa9b44f"),
"email" : "meto93#gmail.com",
"password" : "vpGl+Fjnef616cRgNbCkwaFDpSI=",
"passwordsalt" : "99397F4A9D3A499D96694547667E74595CE994D2E83345D6953EF866303E8B65",
"children" : [
{
"_id" : ObjectId("58daf84977733645eaa9b450"),
"name" : "Mert",
"age" : 5,
"additionalinformation" : "ilk cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
},
{
"_id" : ObjectId("58daf84977733645eaa9b451"),
"name" : "Sencer",
"age" : 7,
"additionalinformation" : "ikinci cocuk",
"creationtime" : ISODate("2017-03-28T23:56:56.952Z"),
"userid" : ObjectId("58daf84877733645eaa9b44f"),
"gender" : null
}
]
}
Job
{
"_id" : ObjectId("58db0a2d77733645eaa9b453"),
"creationtime" : ISODate("2017-03-29T01:13:17.509Z"),
"startingtime" : ISODate("2017-04-03T13:00:00.000Z"),
"endingtime" : ISODate("2017-04-03T17:00:00.000Z"),
"children" : [
ObjectId("58daf84977733645eaa9b450"),
ObjectId("58daf84977733645eaa9b451")
],
"creatorparent" : ObjectId("58daf84877733645eaa9b44f"),
"applicants" : []
}
If I understood it correctly. A similar solution is achievable using MongoDB 3.4's $addFields and $lookup aggregation steps.
Mongo aggregation:
[
{
$addFields: {
"job":"$$ROOT"
}
},
{
$unwind: {
path : "$children"
}
},
{
$lookup: {
"from" : "users",
"localField" : "creatorParent",
"foreignField" : "_id",
"as" : "creatorParent"
}
},
{
$lookup: {
"from" : "users",
"localField" : "children",
"foreignField" : "_id",
"as" : "children"
}
},
{
$group: {
"_id": "$_id",
"job": { "$first": "$job" },
"creatorParent" : { "$first" : "$creatorParent" },
"children": { "$addToSet": { $arrayElemAt: [ "$children", 0 ] } }
}
}
]
The output will look like the following:
{ "_id" : ObjectId("58da9cb6340c630315348114"),
"job" : {
"_id" : ObjectId("58da9cb6340c630315348114"),
"name" : "Developer",
"creatorParent" : ObjectId("58da9c79340c630315348113"),
"children" : [
ObjectId("58da9c6d340c630315348112"),
ObjectId("58da9c5f340c630315348111")
],
"hourly_rate" : 12.0,
"additional_information" : "other infos"
},
"creatorParent" : [
{
"_id" : ObjectId("58da9c79340c630315348113"),
"name" : "The Boss",
"age" : 40.0
}
],
"children" : [
{
"_id" : ObjectId("58da9c5f340c630315348111"),
"name" : "James",
"age" : 28.0
},
{
"_id" : ObjectId("58da9c6d340c630315348112"),
"name" : "Andrew",
"age" : 26.0
}
]}
UPDATE:
If you substitute the last $group stage with this:
{
"_id": "$_id",
"name": { "$first": "$name" },
"jobstatus": { "$first": "$jobstatus" },
"hourlyrate": { "$first":"$hourlyrate" },
"creatorparent" : { "$first" : "$creatorparent" },
"children": { "$addToSet": { $arrayElemAt: [ "$children", 0 ] } }
}
Then you can achieve what you would like to, but in this $group stage you have to specify every field of job one-by-one with the $first expression.