how to join two documents using $lookup mongodb - node.js

I have been trying to join two collection in MongoDb using the aggregate function but it seems it's not working for me, When I run api using lookup it show the me empty collection [],
I have tried with the following.
db.student.aggregate([
{
"$match": {
_id: "63c4c245188267e988d690e2"
},
},
{
"$lookup": {
"from": "wall",
"localField": "_user",
"foreignField": "_id",
"as": "wallpost"
}
}
])
Result:
Here is the result i m getting after lookup :(
[
{
"_id": "63c4c245188267e988d690e2",
"hereFor": [
{
"mainTag": "study",
"subtag": [
"studybuddy",
"findtutor"
]
}
],
"lastName": "Kumar",
"name": "Kamal",
"profilePicture": [
"https://airustudentimages.s3.ca-central-1.amazonaws.com/1673588594404-ba7777ef676f439f86aa612e8be67fd9"
],
"wallpost": []
}
]
Collections
Collection i m using in the query.
Student
student: [
{
"_id": "63c4c245188267e988d690e2",
"name": "Kamal",
"lastName": "Kumar",
"profilePicture": [
"https://airustudentimages.s3.ca-central-1.amazonaws.com/1673588594404-ba7777ef676f439f86aa612e8be67fd9"
],
"hereFor": [
{
"mainTag": "study",
"subtag": [
"studybuddy",
"findtutor"
]
}
],
},
{
"_id": "63c3965c201a1d738ab6867e",
"name": "Suraksha",
"lastName": "Singh",
"profilePicture": [
"https://airustudentimages.s3.ca-central-1.amazonaws.com/1673762449670-a8bdf9b9b0faf3ad84e0a5bc76e32fb8"
],
"hereFor": [
{
"mainTag": "study",
"subtag": [
"studybuddy",
"findtutor"
]
}
],
}
],
Wall
"wall": [
{
"_id": "63c4c92a188267e988d690e3",
"_user": "63c3965c201a1d738ab6867e",
"isSponsered": false,
"description": "Hello test case ",
"tag": {
"mainTag": "hostels"
},
"createdAt": "1673766717308",
"updatedAt": "1673766717308",
},
{
"_id": "63c4cc2b188267e988d690e5",
"_user": "63c3965c201a1d738ab6867e",
"isSponsered": false,
"description": "Hello test case 22 ",
"tag": {
"mainTag": "hostels"
},
"createdAt": "1673766717308",
"updatedAt": "1673766717308",
},
],
Have a look at https://mongoplayground.net/p/2moDXi3lygL

Your query is on Student collection. So the localField should be _id and and the foreignField should be _user (from wall collection).
Then it works fine.
db.student.aggregate([
{
"$match": {
_id: "63c3965c201a1d738ab6867e"
},
},
{
"$lookup": {
"from": "wall",
"localField": "_id",
"foreignField": "_user",
"as": "wallpost"
}
}
])
https://mongoplayground.net/p/r1JeQIlM7AA

You mix up the localField and foreignField.
From Equality Match with a Single Join Condition:
{
$lookup:
{
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
}
}
It should be:
{
"$lookup": {
"from": "wall",
"localField": "_id",
"foreignField": "_user",
"as": "wallpost"
}
}
Demo # Mongo Playgound

Related

How to combine 3 collections MongoDB?

i have 3 collections: Restaurants, Menu and Product.
Their structure:
Restaurants
Menu
Products
I want to make a query with nested arrays. And try:
const restaurant = await Restaurant.aggregate([
{
"$match": { _id: ObjectId(req.params.id) }
},
{
"$lookup": {
"from": "menus",
"localField": "menu",
"foreignField": "_id",
"as": "menu",
}
},
{
"$lookup": {
"from": "products",
"localField": "menu.products",
"foreignField": "_id",
"as": "menu.products"
}
},
])
But this query returns data without menu name:
"menu": {
"products": [
{
"_id": "604f349280a17606402211d3",
"price": 6,
"image": "https://i.pinimg.com/736x/00/67/1e/00671e890191ecfeaf680cbecd3acf3e.jpg",
"name": "Toast with banana",
"description": "210g, Composition: Bread, Nutella, Banana",
"user": "604f349280a17606402211d0",
"__v": 0,
"createdAt": "2021-03-15T10:18:58.220Z",
"updatedAt": "2021-03-15T10:18:58.220Z"
},...]
I just started to study Mongodb, so I don't understand a lot. Please help write a request.
If I wrote something wrong, sorry, English is not my first language :)
It turned out to be done like this
const restaurant = await Restaurant.aggregate([
{
"$match": { _id: ObjectId(req.params.id) }
},
{
"$lookup": {
"from": "menus",
"localField": "menu",
"foreignField": "_id",
"as": "menu",
}
},
{ "$unwind": { "path": "$menu", "preserveNullAndEmptyArrays": true } },
{
"$lookup": {
"from": "products",
"localField": "menu.products",
"foreignField": "_id",
"as": "menu.products"
}
},
{
"$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"hours": { "$first": "$hours" },
"image": { "$first": "$image" },
"phones": { "$first": "$phones" },
"takeAway": { "$first": "$takeAway" },
"description": { "$first": "$description" },
"address": { "$first": "$address" },
"user": { "$first": "$user" },
"menu": { "$push": "$menu" }
}
}
])

MongoDB aggregate and get mismatched results

Hi everyone i have 2 collections named "members" and "offers" in mongoDB. When a member send an offer to another, my web service saves it to offers collection.
"members" collection is like:
[
{
"_id": "5ee00pp0ebfd4432145233344",
"Fname": "John",
"Lname": "Lastname",
"Email": "JohnLastName#gmail.com",
},
{
"_id": "yyyy44p0ebfd4432145233355",
"Fname": "Ashley",
"Lname": "Lastname",
"Email": "AshleyLastName#gmail.com",
},
{
"_id": "yyyy44p0ebfd4432145233355",
"Fname": "Sue",
"Lname": "Lastname",
"Email": "SueLastName#gmail.com",
}
]
when John send an offer to Ashley
"offers" collection is like:
[
{
"_id": "5eea6e62881835271415fd25",
"OfferMail": "JohnLastName#gmail.com",
"Email": "AshleyLastName#gmail.com",
}
]
Now my question is: How can i get all members except Ashley?
Use the $not operator. For example
db.members.find({"Email" : {"$not" : "AshleyLastName#gmail.com"}})
db.members.aggregate([
{
"$lookup": {
"from": "offers",
"localField": "Email",
"foreignField": "Email",
"as": "docuentInB"
}
},
{
$match: {
$expr: { $eq: [{ $size: "$docuentInB" }, 0 ] }
}
},
{
$project: {
docuentInB: 0
}
}
])````

How can I query on a referenced field in MongoDB?

I have two collections, users and posts. The relevant parts of a typical document looks like this:
user
{
"_id": "user1",
"name": "Joe",
"age": 20
}
posts
{
"content": "Yo what's up!",
"created": "2018-02-05T05:00:00.000Z",
"author": "user1"
}
I would like to create a query on the posts collection that returns the following:
{
"content": "Yo what's up!",
"created": "2018-02-05T05:00:00.000Z",
"author": {
"name": "Joe",
"age": 20
}
Is there any way to do this in raw MongoDB?
I'm using the MongoDB Node.js client.
Using aggregation with lookup operator.
db.posts.aggregate([
{"$lookup":{
"from":"users",
"localField":"author",
"foreignField":"_id",
"as":"author"
}},
{"$addFields":{
"author": {"$arrayElemAt":["$author",0]}
}}])
db.posts.aggregate(
// Pipeline
[
// Stage 1
{
$lookup: {
"from": "user",
"localField": "author",
"foreignField": "_id",
"as": "authorobj"
}
},
// Stage 2
{
$project: {
content: 1,
created: 1,
author: {
'name': {
"$arrayElemAt": ["$authorobj.name", 0]
},
'age': {
"$arrayElemAt": ["$authorobj.age", 0]
}
},
}
},
]
);

aggregate $push + $lookup

I need to populate inside array...
messageModel.aggregate([
{"$match": {$and: [
{$or: [{"to": system.mongoose.Types.ObjectId(userId)}, {"from": system.mongoose.Types.ObjectId(userId)}]}
]
}
},
{
"$group": {
"_id": "$conversationId",
"conversation": {"$push": {'from': "$from"}}
}
},
{"$lookup": {
"from": "user",
"localField": "conversation.from",
"foreignField": "_id",
"as": "to"
}},
{"$unwind": {"path": "$conversation.from"}},
{"$project": {
"conversation.from.firstName": "$conversation.from.firstName"
}
}
]
This return empty array what is wrong? it works when I don't use array, if just take $first element... Any solution?

How to use $lookup on embedded document field in mogodb

Please have a look, your help will be appriciated
var user = new Schema({
name: String,
});
var Comments = new Schema({
title : String
, body : String
,user_id : {type: Schema.Types.ObjectId, ref: 'user' }
, date : Date
});
var blog = new Schema({
author : String
, title : String
, body : String
, date : Date
, user_id :{type: Schema.Types.ObjectId, ref: 'user' }
, comments : [Comments]
});
db.blogs.aggregate([
{ $match : { "_id" : ObjectId("57e3b7f4409d80a508d52769") } },
{ $lookup: {from: "users", localField: "user_id", foreignField: "_id", as: "User"} },
])
this returns
[
{
"_id": "57e3b7f4409d80a508d52769",
"author": "Tariq",
"title": "MyfirstPost",
"body": "This is my first post",
"user_id": "57e3b763f7bc810c08f9467a",
"comments": [
{
"title": "hi",
"body": "again i am commenting on this",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c153409d80a508d5276b"
},
{
"title": "hi",
"body": "this is seond comment",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c8632ebca0ee0afb2ac6"
}
],
"__v": 0,
"User": [
{
"_id": "57e3b763f7bc810c08f9467a",
"name": "Tariq",
"username": "teekay",
"password": "123456",
"__v": 0
}
]
}
]
this return result by comparing blog table is and user table _id which is fine .. but I want to get userdetail with each comment by using user_id of “comments.user_id” blog collection and “_id” of collection
should be something like this
"_id": "57e3b7f4409d80a508d52769",
"author": "Tariq",
"title": "MyfirstPost",
"body": "This is my first post",
"user_id": "57e3b763f7bc810c08f9467a",
"comments": [
{
"title": "hi",
"body": "again i am commenting on this",
"user_id": "57e3b763f7bc810c08f9467a",
"_id": "57e3c153409d80a508d5276b",
"User": [
{
"_id": "57e3b763f7bc810c08f9467a",
"name": "Tariq",
"username": "teekay",
"password": "123456",
"__v": 0
}
]
},
You can run an aggregation operation of the pipeline:
db.blogs.aggregate([
{ "$unwind": "$comments" },
{
"$lookup": {
"from": "users",
"localField": "comments.user_id",
"foreignField": "_id",
"as": "comments.user"
}
},
{ "$unwind": "$comments.user" },
{
"$group": {
"_id": "$_id",
"author": { "$first": "$author" },
"title": { "$first": "$title" },
"body": { "$first": "$body" },
"comments": { "$push": "$comments" },
"user_id": { "$first": "$user_id" }
}
},
{
"$lookup": {
"from": "users",
"localField": "user_id",
"foreignField": "_id",
"as": "user"
}
},
{ "$unwind": "$user" },
])

Resources