I need to populate only active records in mongodb - 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")
}]
}]

Related

Why "as" in $lookup is replacing the complete set?

Let me first introduce you to the 2 collections I am using :
Collection 1 : users
> db.users.find().pretty()
{
"_id" : ObjectId("5ee4e727d04e4b4ac1ef115b"),
"name" : "Ashutosh Tiwari",
"age" : 21,
"email" : "ashutosh#gmail.com"
}
{
"_id" : ObjectId("5ee4e727d04e4b4ac1ef115c"),
"name" : "Maximilian",
"age" : 32,
"email" : "max#yahoo.com"
}
Collection 2 : posts
> db.posts.find().pretty()
{
"_id" : ObjectId("5ee51b7ed9f661cad505fcc6"),
"title" : "First One",
"text" : "Hey this is the first Author",
"author" : ObjectId("5ee4e727d04e4b4ac1ef115c"),
"comments" : [
{
"user" : ObjectId("5ee4e727d04e4b4ac1ef115b"),
"comment" : "This is my comment"
}
]
}
{
"_id" : ObjectId("5ee5353cd9f661cad505fcc8"),
"title" : "First One",
"author" : ObjectId("5ee4e727d04e4b4ac1ef115c"),
"comments" : [
{
"user" : ObjectId("5ee4e727d04e4b4ac1ef115b"),
"comment" : "This is my comment"
}
]
}
I want to have the user inside comments array in 2nd Collection(posts) to be replaced by the user who has written that comment.
I have tried the query below but it is replacing the comments section !
> db.posts.aggregate([
{ $lookup:
{from: "users",
localField:"comments.user",
foreignField:"_id",
as:"comments.user"
}
} ]).pretty()
{
"_id" : ObjectId("5ee51b7ed9f661cad505fcc6"),
"title" : "First One",
"text" : "Hey this is the first Author",
"author" : ObjectId("5ee4e727d04e4b4ac1ef115c"),
"comments" : {
"user" : [
{
"_id" : ObjectId("5ee4e727d04e4b4ac1ef115b"),
"name" : "Ashutosh Tiwari",
"age" : 21,
"email" : "ashutosh#gmail.com"
}
]
}
}
{
"_id" : ObjectId("5ee5353cd9f661cad505fcc8"),
"title" : "First One",
"author" : ObjectId("5ee4e727d04e4b4ac1ef115c"),
"comments" : {
"user" : [
{
"_id" : ObjectId("5ee4e727d04e4b4ac1ef115b"),
"name" : "Ashutosh Tiwari",
"age" : 21,
"email" : "ashutosh#gmail.com"
}
]
}
}
So, here, whole comments section is now replaced whereas I wanted to have the details in comments.user section so I could see the comment and the user who has posted that comment.
you need to unwind the comments array first
your query may look something like this
db.posts.aggregate([
{
$unwind: "$comments" // unwind the comments array to get a stream of documents, each document has only one comment
},
{
$lookup: {
from: "users",
localField: "comments.user",
foreignField: "_id",
as: "comments.user"
}
},
{
$unwind: "$comments.user" // we know there is only one user inside a single comment, so we can unwind this user array to be an object too (as the lookup returns an array)
},
{
$group: { // then do a group by the document _id to get unique documents with comments array instead of the same document duplicated with different comments
_id: "$_id",
author: {
$first: "$author"
},
text: {
$first: "$text"
},
title: {
$first: "$title"
},
comments: {
$push: "$comments"
}
}
}
])
you can test it here
hope it helps
You can handle it in the projection.
db.posts.aggregate([
{ $lookup:
{from: "users",
localField:"comments.user",
foreignField:"_id",
as:"cu"
}
},
{$unwind:{path:"$cu"}},
{
$project:{
"title":1,
"text":1,
"author":1,
"comments":{
user: "$cu",
comment: { $arrayElemAt: [ "$comments.comment", 0 ] },
}
}
}
])

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"
]
}

MongoDB aggregation $lookup pipeline convert from array of objects to flat array [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"
]
}

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"
]
}

using match for both linked collection of mongo in lookup

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
}
]);