using match for both linked collection of mongo in lookup - mongodb

I have two collections - orders, feedback
Orders:
{
"restaurantId" : NumberInt(138),
"referenceNo" : "1980DBF5",
"orderId" : "1045593",
"userId" : NumberInt(6664960),
"userEmail" : "user#g.com",
"firstName" : "User"
}
Feedbacks:
{
"rating" : NumberInt(4),
"additionalComments" : "it is working",
"referenceNo" : "7D02097F",
"productId" : NumberInt(1),
"restaurantId" : NumberInt(138),
"orderType" : "1"
}
I need to make a join on these two collections.
Also, there will be filter inputs on rating, referenceNo, userEmail, firstName.
How can I use match to get data from two collections?
This is my aggregate query:
[
{
"$lookup":
{
"from": "orders",
"localField": "referenceNo",
"foreignField": "referenceNo",
"as": "data"
}
}
]
I am using this query on feedback model.
The data that I get is:
{
"rating" : NumberInt(4),
"additionalComments" : "it is working",
"referenceNo" : "7D02097F",
"productId" : NumberInt(1),
"restaurantId" : NumberInt(138),
"orderType" : "1"
"data": [{
"restaurantId" : NumberInt(138),
"referenceNo" : "1980DBF5",
"orderId" : "1045593",
"userId" : NumberInt(6664960),
"userEmail" : "user#g.com",
"firstName" : "User"
}]
}
Also, would it be possible to add limits here?
Earlier I was using this on orders -
mQuery.skip(Number(paginate.offset)).limit(Number(paginate.limit));

Check if this helps....
db.feedbacks.aggregate([ {
$lookup:
{
from: "users",
localField: "whatever",
foreignField: "whatever",
as: "data"
}},
{
$unwind: "$data"
},
{
$match:
{
"data.orderId":"1045593"} //conditions
},
{
$limit:1 //limit
}
]);

Related

Unable to aggregate two collections using lookup in MongoDB Atlas

I have an orders collection that looks like this:
{
"_id" : "wJNEiSYwBd5ozGtLX",
"orderId" : 52713,
"createdAt" : ISODate("2020-01-31T04:34:13.790Z"),
"status" : "closed",
"orders" : [
{
"_id" : "ziPzwLuZrz9MNkaRT",
"productId" : 10290,
"quantity" : 2
}
]
}
I have an products collection that looks like this
{
"_id" : "238cwwLkZa6gKNN86",
"productId" : 10290,
"title" : "Product Title",
"price" : 9.9
}
I am trying to merge the price information into the orders information.
Something like:
{
"_id" : "wJNEiSYwBd5ozGtLX",
"orderId" : 52713,
"createdAt" : ISODate("2020-01-31T04:34:13.790Z"),
"status" : "closed",
"orders" : [
{
"_id" : "ziPzwLuZrz9MNkaRT",
"productId" : 10290,
"quantity" : 2,
"price": 9.9
}
]
}
If I try a $lookup command on MongoDB Atlas Dashboard like this:
{
from: 'products',
localField: 'orders.productId',
foreignField: 'productId',
as: 'priceInfo'
}
The aggregated output is (not what I wanted):
{
"_id" : "wJNEiSYwBd5ozGtLX",
"orderId" : 52713,
"createdAt" : ISODate("2020-01-31T04:34:13.790Z"),
"status" : "closed",
"orders" : [
{
"_id" : "ziPzwLuZrz9MNkaRT",
"productId" : 10290,
}
],
"priceInfo": [
{
"_id" : "238cwwLkZa6gKNN86",
"productId" : 10290,
"title" : "Product Title",
"price" : 9.9
}
]
}
I do not need a separate priceInfo array. It will be best if I have the product details information merged into the "orders" array. What should be the aggregation lookup syntax to achieve the desired output?
Demo - https://mongoplayground.net/p/bLqcN7tauWU
Read - $lookup $unwind $first $set $push $group
db.orders.aggregate([
{ $unwind: "$orders" }, // break array of orders into individual documents
{
$lookup: { // join
"from": "products",
"localField": "orders.productId",
"foreignField": "productId",
"as": "products"
}
},
{
$set: {
"orders.price": { "$arrayElemAt": [ "$products.price", 0 ] } // set the price
}
},
{
$group: { // group records back
_id: "$_id",
createdAt: { $first: "$createdAt" },
status: { $first: "$status" },
orderId: { $first: "$orderId" },
orders: { $push: "$orders" }
}
}
])

Mongodb $lookup in data aggregation - localField attribute character issue

I was trying to join multiple collections in MongoDB using the aggregate $lookup.The issue I am facing right now $lookup localField attribute does not accept $ character.
I have following three collections.
student
{
"_id" : ObjectId("5db12e6dfc368dff1cfc30e5"),
"studentId" : "S97YAREA51",
"name" : "Has Maara duwa",
"age" : 22
}
course
{
"_id" : ObjectId("5db12e6dfc368dff1cfc20e5"),
"courseId" : "C04865690",
"courseName" : "Love and Empathy"
}
studentCourse
{
"_id" : ObjectId("5db12e6dfc368dff1cfc10e5"),
"student" : {
"$ref" : "student",
"$id" : ObjectId("5db12e6dfc368dff1cfc30e5")
},
"course" : {
"$ref" : "course",
"$id" : ObjectId("5db12e6dfc368dff1cfc20e5")
}
}
I need to update studentCourse collection records to something like below.
{
"_id" : ObjectId("5db12e6dfc368dff1cfc10e5"),
"student" : {
"$ref" : "student",
"$id" : ObjectId("5db12e6dfc368dff1cfc30e5")
},
"course" : {
"$ref" : "course",
"$id" : ObjectId("5db12e6dfc368dff1cfc20e5")
},
"studentId" : "S97YAREA51",
"courseId" : "C04865690"
}
I tried to create the following aggregation query, but it was failing due to localField does not accept $ character. I would be much appreciated if somebody provides me a simple solution for this matter.
db.studentCourse.aggregate([
{
$lookup:{
from: "student",
localField: "student.$id",
foreignField: "_id",
as: "student"
}
},
{ $unwind:"$student" }, // $unwind used for getting data in object or for one record only
{
$lookup:{
from: "course",
localField: "course.$id",
foreignField: "_id",
as: "course"
}
},
{ $unwind:"$course" },
// define which fields are you want to fetch
{
$project:{
"_id" : 1,
"student" : 1,
"course" : 1,
"studentId" : "$student.studentId",
"courseId" : "$course.courseId",
}
}
]);

Join Multiple Tables MongoDB and returned merged result

I have two collections one is user and other is address.
User document has list which contains the publicId of addresses.
I am writing an API to fetch users. How can I return the merged result of user and addresses documents?
User :
{
"_id" : ObjectId("5684f3c454b1fd6926c324fd"),
"email" : "user#example.com",
"userId" : "userId",
"addresses" : ["A1234","A5678"]
}
Address :
{
"_id" : ObjectId("56d82612b63f1c31cf906004"),
"publicId" : "A1234"
"addressLine1" : "AD1",
"addressLine2" : "AD1",
"pin" : "001"
}
{
"_id" : ObjectId("56d82612b63f1c31cf906005"),
"publicId" : "A5678"
"addressLine1" : "AD2",
"addressLine2" : "AD2",
"pin" : "002"
}
What I am trying to achieve is following
{
"_id" : ObjectId("5684f3c454b1fd6926c324fd"),
"email" : "user#example.com",
"userId" : "userId",
"addresses" : [
{
"publicId" : "A1234"
"addressLine1" : "AD1",
"addressLine2" : "AD1",
"pin" : "001"
},
{
"publicId" : "A5678"
"addressLine1" : "AD2",
"addressLine2" : "AD2",
"pin" : "002"
}
]
}
how can I achieve this using aggregate query?
for that you can use $lookup stage from aggregation framework:
db.user.aggregate([
{$lookup:
{
from : 'addresses',
localField: 'Addresses',
foreignField: 'publicId',
as: 'Addresses'
}
},
{$project: {'Addresses._id': 0} }
]).pretty()
for using $lookup (similar to left outer join) you need to use MongoDB version 3.2 or above.
I got it working. Following is the aggregate query I used.
db.user.aggregate([
{
$unwind: "$addresses"
},
{
$lookup:
{
from: "address",
localField: "addresses",
foreignField: "publicId",
as: "addresses"
}
},
{
$match: {
"userId":"userId",
"addresses": { $ne: [] }
}
}
])

$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.

I need to populate only active records in mongodb

I am trying to lookup child collection in mongodb using moongose in node.js but it will lookup all child records, i want to lookup only active records.
Parent Collection is Users
Child Collection - Post which contains post published by user and have a user_id as refrence of Users collection. I tried below query but no luck
User Collection Sample :
{
"_id" : ObjectId("584016e28880811461000007"),
"fname" : "Test",
"lname" : "user",
"email" : "test#user.com",
},
{
"_id" : ,
"fname" : "Test2",
"lname" : "user2",
"email" : "test2#user.com",
}
Post Collection Sample :
{
"_id" : ObjectId("5863aed8cafb42674600000e"),
"user_id" : ObjectId("584016e28880811461000007"),
"title" : "Post 1",
"is_deleted" : false
},
{
"_id" : ,
"user_id" : ObjectId("584016e28880811461000007"),
"title" : "Post 2",
"is_deleted" : true
}
Query I tried :
Users.collection.aggregate([
{ $lookup: {from: "Posts", localField: "_id", foreignField: "user_id", as: "Posts"} },
{ $match : { $or : [{"Posts._id" : {$exists : true}, "Posts.is_deleted" : false}] }},
{$project: {fname: "$fname", lname : "$lname", email : "$email", "publishedPosts" : {$size : "$Posts"}}}
])
Result i got from above code :
[
{"fname" : "Test", "lname" : "user", "email" : "test#user.com", "publishedPosts" : 2},
{"fname" : "Test2", "lname" : "user2", "email" : "test2#user.com", "publishedPosts" : 0}
]
Result Expected :
[
{"fname" : "Test", "lname" : "user", "email" : "test#user.com", "publishedPosts" : 1},
{"fname" : "Test2", "lname" : "user2", "email" : "test2#user.com", "publishedPosts" : 0}
]
it lookup all post, whther is_deleted is false or true
Please help me with some similar query which will work for me
The $match stage you're using is wrong. The first condition ( {"Posts._id" : {$exists : true} ) is useless because each document has to have an _id field ( see mongodb _id field for details ).
Update: Do the $match stage before $lookup for better performances. Lookup from Posts to Users, then unwind Users and group documents for the sum
this query return the result you're expecting:
db.Posts.aggregate([
{
$match:{
is_deleted:false
}
},
{
$lookup:{
from:"Users",
localField:"user_id",
foreignField:"_id",
as:"Users"
}
},
{
$unwind:"$Users"
},
{
$group:{
_id:"$user_id",
lname:{
$first:"$Users.lname"
},
fname:{
$first:"$Users.fname"
},
email:{
$first:"$Users.email"
},
publishedPosts:{
$sum:1
}
}
}
])
output:
{ "_id" : ObjectId("584016e28880811461000007"), "lname" : "user", "fname" : "Test", "email" : "test#user.com", "publishedPosts" : 1 }
you can try this , it working
shop collection
{
name:"shop1",
status:true,
_id : ObjectId("583d0c1f2bd2cbdb117053c5")
}
{
name:"shop2",
status:false,
_id : ObjectId("583d0c1f2bd2cbdb117053c6")
}
order collection
{
orderNo:1,
price:100,
product:"product1",
shop:ObjectId("583d0c1f2bd2cbdb117053c5")
}
try this
db.getCollection('orders').aggregate([
{
$lookup:
{
from: "shop",
localField: "shop",
foreignField: "_id",
as: "shopData"
}
},
{ $match : { $or: [ { "shopData.status": true}] } }
])
result :
[{
orderNo:1,
price:100,
product:"product1",
shop:[{
name:"shop1",
status:true,
_id : ObjectId("583d0c1f2bd2cbdb117053c5")
}]
}]