how to make mongodb lookup match from both collection - mongodb

Database structure:
db={
"collection": [
{
"key": 15,
"name": "srk",
},
{
"key": 12,
"name": "suman",
}
],
"other": [
{
"key": 15,
"name": "miki",
"category": "dish"
},
{
"key": 15,
"name": "mira",
"category": "air"
},
{
"key": 15,
"name": "manas",
"category": "air"
},
{
"key": 166,
"name": "sibu",
"category": "dish"
}
]
}
query i am trying:
db.collection.aggregate([
{
$lookup: {
from: "other",
localField: "key",
foreignField: "key",
as: "inventory_docs"
}
},
{
$match: {
key: 15,
{ "inventory_docs":
{ category: 'dish'}
}
}
}
])
I am not getting result here while making query in mongodb.
Please have a look , tell me where i am doing wrong in the query.
I am matching key with 15 from both the collections and category with 'Dish' from foreign collection

Though you have solved your problem self.
but query needs to optimize
if you do Lookup first, you will get data of "key": 12 or all other keys.
just to optimize query :
db.collection.aggregate([
{
$match : { key: 15 }
},
{
$lookup: {
from: "other",
localField: "key",
foreignField: "key",
as: "inventory_docs"
}
},
{
$unwind: "$inventory_docs"
},
{
$match: {
"inventory_docs.category": "dish"
}
}
])

db.collection.aggregate([
{
$lookup: {
from: "other",
localField: "key",
foreignField: "key",
as: "inventory_docs"
}
},
{
$unwind: "$inventory_docs"
},
{
$match: {
key: 15,
"inventory_docs.category": "dish"
}
}
])

Related

Update Mongo collection fields with values from other collection

I'm refactoring my Mongo database to put users in a separate collection, and can't figure out how to save the result of this updated query so that plan names become user IDs:
db.plans.aggregate([{
$lookup: {
from: "users",
localField: "person",
foreignField: "name",
as: "person"
}
}, {
$lookup: {
from: "users",
localField: "place",
foreignField: "name",
as: "place"
}
}, {
$unwind: {
path: "$person"
}
}, {
$unwind: {
path: "$place"
}
},
{
$set: {
"person": "$person.id",
"place": "$place.id",
}
}
])
For example from this:
{
"_id": "aeaab905-2d8b-4e26-9244-918956496c35",
"id": "aeaab905-2d8b-4e26-9244-918956496c35",
"person": "Alice",
"place": "Bob"
}
to this:
{
"_id": "aeaab905-2d8b-4e26-9244-918956496c35",
"id": "aeaab905-2d8b-4e26-9244-918956496c35",
"person": "a7609095-869e-4800-9fac-fefc373c37a5",
"place": "2bd8f68d-721a-4106-bd7f-951236c3593d"
}
where db.users is:
[{
"_id": "a7609095-869e-4800-9fac-fefc373c37a5",
"id": "a7609095-869e-4800-9fac-fefc373c37a5",
"name": "Alice"
},
{
"_id": "2bd8f68d-721a-4106-bd7f-951236c3593d",
"id": "2bd8f68d-721a-4106-bd7f-951236c3593d",
"name": "Bob"
}]
As Alex Blex pointed out, $merge worked:
db.plans.aggregate([{
$lookup: {
from: "users",
localField: "person",
foreignField: "name",
as: "person"
}
}, {
$lookup: {
from: "users",
localField: "place",
foreignField: "name",
as: "place"
}
}, {
$unwind: {
path: "$person"
}
}, {
$unwind: {
path: "$place"
}
},
{
$set: {
"person": "$person.id",
"place": "$place.id",
}
}, { $merge: { into: "plans", on: "_id", whenMatched: "replace", whenNotMatched: "insert" } }
])

mongodb $lookup - suppress non-matching documents

I only want to see matching documents, i.e. only T3 in the example below. I can find the matching documents between lotterytickets (many documents) and lotterydrawing (only a few documents).
How can I filter out the non-matching documents? Basically, I'd not like to see documents with the condition drawnticket==[], but I haven't found the conditional code to apply.
Any help would be appreciated. Thank you in advance
Configuration:
db={
"lotteryticket": [
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a2e"),
"ticket": "T1",
"player": "Alice"
},
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a2f"),
"ticket": "T2",
"player": "Bob"
},
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a33"),
"ticket": "T3",
"player": "Charles"
}
],
"lotterydrawing": [
{
"_id": ObjectId("63309480b749b733c087b758"),
"ticket": "T3"
},
{
"_id": ObjectId("63309480b749b733c087b759"),
"ticket": "T9"
},
{
"_id": ObjectId("63309480b749b733c087b75a"),
"ticket": "T77"
}
]
}
Query:
db.lotteryticket.aggregate([
{
$lookup: {
from: "lotterydrawing",
localField: "ticket",
foreignField: "ticket",
as: "drawnticket",
}
}
])
Result:
[
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a2e"),
"drawnticket": [],
"player": "Alice",
"ticket": "T1"
},
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a2f"),
"drawnticket": [],
"player": "Bob",
"ticket": "T2"
},
{
"_id": ObjectId("6021ce0cb4d2c2b4f24c3a33"),
"drawnticket": [
{
"_id": ObjectId("63309480b749b733c087b758"),
"ticket": "T3"
}
],
"player": "Charles",
"ticket": "T3"
}
]
https://mongoplayground.net/p/bYcLEzrF5QT
Add a match stage, to filter stages with the empty drawn tickets. Like this:
db.lotteryticket.aggregate([
{
$lookup: {
from: "lotterydrawing",
localField: "ticket",
foreignField: "ticket",
as: "drawnticket",
}
},
{
"$match": {
$expr: {
"$gt": [
{
$size: "$drawnticket"
},
0
]
}
}
}
])
Playground.
try this query
db.lotteryticket.aggregate([
{
$lookup: {
from: "lotterydrawing",
localField: "ticket",
foreignField: "ticket",
as: "drawnticket"
}
},
{
"$match": {
drawnticket: {
$exists: true,
$ne: []
}
}
}
])
Playground.

MongoDB $lookup on array of objects with reference objectId

I have Orders collection and iam getting the data from it as shown below:
[
{
"_id": "628216b7b30bb8aa80c8fd1a",
"promotionsDetails": {
"companyTotalPrice": 27,
"promotionsData": [
{
"_id": "621de063bb5f9f0bf510897f",
"price": 27,
"companyId": "621dd85eb45ca2ae292d9a36"
},
{
"_id": "621de063bb5f9f0bf510897d",
"price": 19,
"companyId": "621dd85eb45ca2ae292d9a32"
}
]
}
},
{
"_id": "628214fcb30bb8aa80c8fd18",
"promotionsDetails": {
"companyTotalPrice": 46,
"promotionsData": [
{
"_id": "621de063bb5f9f0bf510897f",
"price": 46,
"companyId": "621dd85eb45ca2ae292d9a32",
}
]
},
}
]
what I am trying to do is to get the company details from the companies collection using the companyId objectId in each object in the array, like below:
[
{
"_id": "628216b7b30bb8aa80c8fd1a",
"promotionsDetails": {
"companyTotalPrice": 27,
"promotionsData": [
{
"_id": "621de063bb5f9f0bf510897f",
"price": 27,
"companyId": "621dd85eb45ca2ae292d9a36",
"companyData": { "title": "..." }
},
{
"_id": "621de063bb5f9f0bf510897d",
"price": 19,
"companyId": "621dd85eb45ca2ae292d9a32",
"companyData": { "title": "..." }
}
]
}
},
{
"_id": "628214fcb30bb8aa80c8fd18",
"promotionsDetails": {
"companyTotalPrice": 46,
"promotionsData": [
{
"_id": "621de063bb5f9f0bf510897f",
"price": 46,
"companyId": "621dd85eb45ca2ae292d9a32",
"companyData": { "title": "..." }
}
]
}
}
]
i have tried to use lookup and pipeline, but I'm not getting the desired result, thanks!
Actuality $lookup supports arrays, so there is no need to $unwind and change the structure. This will return your expected results:
db.Orders.aggregate([
{
$lookup: {
from: "Company",
localField: "promotionsDetails.promotionsData.companyId",
foreignField: "_id",
as: "companyfullData"
}
},
{
$set: {
"promotionsDetails.promotionsData": {
$map: {
input: "$promotionsDetails.promotionsData",
in: {
$mergeObjects: [
"$$this",
{
companyData: {
$arrayElemAt: [
"$companyfullData",
{$indexOfArray: ["$companyfullData.id", "$$this.id"]}
]
}
}
]
}
}
}
}
},
{$unset: "companyfullData"}
])
Playground
Here, to make it more clear take a look at Mongo playground
db.Orders.aggregate([
{
$unwind: "$promotionsDetails.promotionsData"
},
{
"$lookup": {
"from": "Company",
"localField": "promotionsDetails.promotionsData.companyId",
"foreignField": "_id",
"as": "promotionsDetails.promotionsData.companyData"
}
},
])

How to aggregate nested lookup array in mongoose?

I have a problem with how to lookup nested array, for example i have 4 collections.
User Collection
"user": [
{
"_id": "1234",
"name": "Tony",
"language": [
{
"_id": "111",
"language_id": "919",
"level": "Expert"
},
{
"_id": "111",
"language_id": "920",
"level": "Basic"
}
]
}
]
Language Collection
"language": [
{
"_id": "919",
"name": "English"
},
{
"_id": "920",
"name": "Chinese"
}
]
Job
"job": [
{
"_id": "10",
"title": "Programmer",
"location": "New York"
}
],
CvSubmit Collection
"cvsubmit": [
{
"_id": "11",
"id_user": "1234",
"id_job": "11"
}
]
And my query aggregation is:
db.cvsubmit.aggregate([
{
$lookup: {
from: "user",
localField: "id_user",
foreignField: "_id",
as: "id_user"
}
},
{
$lookup: {
from: "language",
localField: "id_user.language.language_id",
foreignField: "_id",
as: "id_user.language.language_id"
}
},
])
But the result is:
[
{
"_id": "11",
"id_job": "11",
"id_user": {
"language": {
"language_id": [
{
"_id": "919",
"name": "English"
},
{
"_id": "920",
"name": "Chinese"
}
]
}
}
}
]
I want the result like this, also showing all user data detail like name:
[
{
"_id": "11",
"id_job": "11",
"id_user": {
"_id": "1234",
"name": "Tony"
"language": [
{
"_id": "919",
"name": "English",
"Level": "Expert"
},
{
"_id": "920",
"name": "Chinese",
"level": "Basic"
}
]
}
}
]
Mongo Playground link https://mongoplayground.net/p/i0yCucjruey
Thanks before.
$lookup with user collection
$unwind deconstruct id_user array
$lookup with language collection and return in languages field
$map to iterate look of id_user.language array
$reduce to iterate loop of languages array returned from collection, check condition if language_id match then return name
db.cvsubmit.aggregate([
{
$lookup: {
from: "user",
localField: "id_user",
foreignField: "_id",
as: "id_user"
}
},
{ $unwind: "$id_user" },
{
$lookup: {
from: "language",
localField: "id_user.language.language_id",
foreignField: "_id",
as: "languages"
}
},
{
$addFields: {
languages: "$$REMOVE",
"id_user.language": {
$map: {
input: "$id_user.language",
as: "l",
in: {
_id: "$$l._id",
level: "$$l.level",
name: {
$reduce: {
input: "$languages",
initialValue: "",
in: {
$cond: [
{ $eq: ["$$this._id", "$$l.language_id"] },
"$$this.name",
"$$value"
]
}
}
}
}
}
}
}
}
])
Playground
You database structure is not accurate as per NoSQL, there should be max 2 collections, loot of join using $lookup and $unwind will cause performance issues.

how to transform data with 3 collection and $looup

I have three collection wanted to fetch records bases on their reference id, I got the result but wanted to transform the data how to make it.
db.post.aggregate([
{
$lookup: {
from: "users",
localField: "created_by",
foreignField: "_id",
as: "users"
}
},
{
$lookup: {
from: "comments",
let: {
p_id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$post_id",
"$$p_id"
]
}
}
}
],
as: "comments"
}
},
{
$lookup: {
from: "users",
localField: "comments.sender_id",
foreignField: "_id",
as: "commented_user"
}
},
])
I am getting this result but what I want merge the commented_user into comments mean who has comments fetch the record.
[
{
"_id": ObjectId("5eeb02881982961ada625c7d"),
"commented_user": [
{
"_id": ObjectId("5e4d0973babf2b74ca868f4d"),
"first_name": "James",
"last_name": "Smith",
"timestamp": 1.582106995137e+12
}
],
"comments": [
{
"_id": ObjectId("5eeb08e26fb7f270e4077617"),
"date": 1.592461538923e+12,
"post_id": ObjectId("5eeb02881982961ada625c7d"),
"sender_id": ObjectId("5e4d0973babf2b74ca868f4d"),
"text": "Nice One "
}
],
"created_by": ObjectId("5e4e74eb380054797d9db623"),
"created_users": [],
"date": 1.589441206774e+12,
"title": "Covid19"
}
]
Would better if I get each commented detail under comments like below ?
"comments": [
{
"_id": ObjectId("5eeb08e26fb7f270e4077617"),
"date": 1.592461538923e+12,
"post_id": ObjectId("5eeb02881982961ada625c7d"),
"sender_id": ObjectId("5e4d0973babf2b74ca868f4d"),
"text": "Nice One ",
"commented_user": [
{
"_id": ObjectId("5e4d0973babf2b74ca868f4d"),
"first_name": "James",
"last_name": "Smith",
"timestamp": 1.582106995137e+12
}
],
}
],
Here is mongoplayground https://mongoplayground.net/p/uw0kMTChFa0
You could use $set and $unset or $project to format the outputs
Example with unset or Example with project
Updated Example. You need to unwind the comments array then perform lookup for each comment to get the commented user.
db.post.aggregate([
{
$lookup: {
from: "users",
localField: "created_by",
foreignField: "_id",
as: "created_users"
}
},
{
$lookup: {
from: "comments",
let: {
p_id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$post_id",
"$$p_id"
]
}
}
}
],
as: "comments"
}
},
{
$unwind: "$comments"
},
{
$lookup: {
from: "users",
localField: "comments.sender_id",
foreignField: "_id",
as: "commented_user"
}
},
{
$set: {
"comments.commented_user": "$commented_user",
}
},
{
$unset: "commented_user"
}
])