How to use mongoose lookup child match? [duplicate] - mongodb

This question already has an answer here:
Aggregation filter after $lookup
(1 answer)
Closed 5 years ago.
Sorry my English is bad...
How to use mongoose lookup child match?
My query is
categorys.aggregate([{
"$sort": {
"order": 1,
"id": 1
}
},
{
"$lookup": {
"localField": "id",
"from": "categorys",
"foreignField": "parentId",
"as": "child"
}
},
{
"$match": {
see: true,
depth: 1
}
}
]).exec(function(err, Categorys)
is result
{
"_id": "596e237c414f2137b0c4e9c2",
"id": 3,
"name": "DB",
"address": "DB",
"parentId": 0,
"depth": 1,
"see": true,
"__v": 0,
"child": [{
"_id": "596e24701e1bd30dc415b894",
"id": 5,
"name": "Mongodb",
"address": "Mongodb",
"parentId": 3,
"depth": 2,
"see": true,
"__v": 0
},
{
"_id": "596e24821e1bd30dc415b895",
"id": 6,
"name": "mssql",
"address": "mssql",
"parentId": 3,
"depth": 2,
"see": false,
"__v": 0
}
]
}]
I don't look result in mssql (see:false) how about match?
Help me!

You can use $filter in $project stage if you want to match in child array. like bellow.
categorys.aggregate([
{
"$sort": {
"order": 1,
"id": 1
}
},
{
"$lookup": {
"localField": "id",
"from": "categorys",
"foreignField": "parentId",
"as": "child"
}
},
{
$project: {
name: 1,
address: 1,
// ... as you need
child: {
$filter: {
input: "$child",
as: "item",
cond: {
$and: [
{$eq: ["$$item.see", true]},
{$eq: ["$$item.depth", 2]}
]
}
}
}
}
}
])
N.B: If you want to use match condition for parent field like "depth":1,"see":true, then you should use that $match stage before $lookup
categorys.aggregate([
{$match:{//parent field match condition first}},
{$sort:{}},
{$lookup:{}},
{$project:{//for child}}
]);

Related

How to replace array of object containing ids with the data using MongoDB aggregation

I am having a collection which contains the data like the following and want to have the desirable output which I have mentioned below.
db={
collectionA: [
{
"id": ObjectId("63b7c24c06ebe7a8fd11777b"),
"uniqueRefId": "UUID-2023-0001",
"products": [
{
"productIndex": 1,
"productCategory": ObjectId("63b7c24c06ebe7a8fd11777b"),
"productOwners": [
ObjectId("63b7c2fd06ebe7a8fd117781")
]
},
{
"productIndex": 2,
"productCategory": ObjectId("63b7c24c06ebe7a8fd11777b"),
"productOwners": [
ObjectId("63b7c2fd06ebe7a8fd117781"),
ObjectId("63b7c12706ebe7a8fd117778")
]
},
{
"productIndex": 3,
"productCategory": "",
"productOwners": ""
}
]
}
],
collectionB: [
{
"_id": ObjectId("63b7c2fd06ebe7a8fd117781"),
"fullname": "Jim Corbett",
"email": "jim.corbett#pp.com"
},
{
"_id": ObjectId("63b7c12706ebe7a8fd117778"),
"fullname": "Carry Minatti",
"email": "carry.minatty#pp.com"
},
]
}
Desirable Output = [
{
"id": ObjectId("507f1f77bcf86cd799439011"),
"uniqueRefId": "UUID-2023-0001",
"products": [
{
"productIndex": 1,
"productCategory": ObjectId('614g2f77bff86cd755439021'),
"productOwners": [
{
"_id": ObjectId("63ac1e59c0afb8b6f2d41acd"),
"fullname": "Jim Corbett",
"email": "jim.corbett#pp.com"
}
]
},
{
"productIndex": 2,
"productCategory": ObjectId('614g2f77bff86cd755439021'),
"productOwners": [
{
"_id": ObjectId("63ac1e59c0afb8b6f2d41acd"),
"fullname": "Jim Corbett",
"email": "jim.corbett#pp.com"
},
{
"_id": ObjectId("63ac1e59c0afb8b6f2d41ace"),
"fullname": "Carry Minatti",
"email": "carry.minatty#pp.com"
}
]
},
{
"productIndex": 3,
"productCategory": "",
"productOwners": ""
}
]
}
]
In the collectionA we are having other documents as well, its not just one document.
Similarly for collectionB we are having other documents too.
How we can get this desirable output?
I am expecting the mongodb query for getting this solution.
I have implemented the lookup like the following
db.collectionA.aggregate([
{
"$lookup": {
"from": "collectionB",
"localField": "products.productOwners",
"foreignField": "_id",
"as": "inventory_docs"
}
}
])
You can try this:
db.collectionA.aggregate([
{
"$unwind": "$products"
},
{
"$lookup": {
"from": "collectionB",
"localField": "products.productOwners",
"foreignField": "_id",
"as": "products.productOwners"
}
},
{
"$group": {
"_id": {
id: "$id",
uniqueRefId: "$uniqueRefId"
},
"products": {
"$push": "$products"
}
}
},
{
"$project": {
id: "$_id.id",
uniqueRefId: "$_id.uniqueRefId",
products: 1,
_id: 0
}
}
])
Playground link.
In this query, we do the following:
First we unwind the products array, using $unwind.
Then we calculate productOwners, using $lookup.
Then we group the unwinded elements, using $group.
Finally we, project the desired output using $project.

MongoDB Aggregate - Match documents with id and give result which id not exist on collection B

Collection A:
[{
"_id": 1,
"operation":"SEC",
"name":"x"
},{
"_id": 2,
"operation": "SEC",
"name": "y"
},
{
"_id": 3,
"operation": "SEC",
"name": "z"
}]
Collection B:
[{
"user": 1,
"operation":"SEC",
"name":"x",
"date": "2022-10-25"
},{
"user": 2,
"operation":"SEC",
"name":"y",
"date": "2022-10-25"
}
]
Expected output:
[
{
"_id": 3,
"operation": "SEC",
"name": "z"
}
]
I have two collections and I want to match from the first collection to the second collection by date and want to get only those that are not in the second collection.
You can use the following aggregation pipeline in order to achieve your desired outpu:
[
{
"$lookup": {
"from": "collectionB",
"localField": "_id",
"foreignField": "user",
"as": "collectionB"
}
},
{
$match: {
collectionB: {
$size: 0
}
}
},
{
$project: {
collectionB: 0
}
}
]
Please note that this is an efficient solution. You probably should add a $match step at the beginning in order to limit your results.

mongodb $lookup with findOne mode

I want to join two mongodb collections, collectionA and collectionB.
For each document in collectionA I want to check if exists a coincidence in collectionB.
If I do it in a $lookup, it returns all the documents joined, but I would like the search in collectionB stops as soon as one coincidence ​is found (kind of a mongodb findOne). My concern is the performance, I know I could get just the element 0 from the array.
Is there a way to do it using the mongodB aggregation framework?
Example:
collectionA:
[
{
"_id": 1,
"item": "almonds"
},
{
"_id": 2,
"item": "pecans"
}
]
colectionB:
[
{
"_fid": 1,
"date": "2021-01-10"
},
{
"_fid": 1,
"date": "2021-01-11"
},
{
"_fid": 1,
"date": "2021-01-12"
},
{
"_fid": 2,
"date": "2021-01-03"
}
]
$lookup mongoDb
db.colectionA.aggregate([
{
"$lookup": {
"from": "colectionB",
"localField": "_id",
"foreignField": "_fid",
"as": "matches"
}
}
])
Result
[
{
"_id": 1,
"item": "almonds",
"matches": [
/* I don't want this array, with 1 element would be enough */
{
"_fid": 1,
"_id": ObjectId("5a934e000102030405000002"),
"date": "2021-01-10"
},
{
"_fid": 1,
"_id": ObjectId("5a934e000102030405000003"),
"date": "2021-01-11"
},
{
"_fid": 1,
"_id": ObjectId("5a934e000102030405000004"),
"date": "2021-01-12"
}
]
},
{
"_id": 2,
"item": "pecans",
"matches": [
{
"_fid": 2,
"_id": ObjectId("5a934e000102030405000005"),
"date": "2021-01-03"
}
]
}
]
You can test on this mongo playground.
Thanks in advance
If you're using at least MongoDB 3.6, you can execute an aggregation pipeline on a joined collection. It might look like this:
db.colectionA.aggregate([
{
"$lookup": {
"from": "colectionB",
"as": "matches",
"let": {
"fid": "$_id"
},
"pipeline": [
{
"$match": {
"$expr": {
"$eq": [
"$_fid",
"$$fid"
]
}
}
},
{
"$limit": 1
}
]
}
}
])
Working Mongo playground

How to add embedded field with matching documents

I'm using Python with pymongo to query from the database.
I have 3 different collections:
1st:
# Projects collection
{
"_id": "A",
},
{
"_id": "B",
},
{
"_id": "C"
},
..
2nd:
# Episodes collection
{
"_id": "A/Episode01",
"project": "A",
"name": "Episode01"
},
{
"_id": "A/Episode02",
"project": "A",
"name": "Episode02"
},
{
"_id": "B/Episode01",
"project": "B",
"name": "Episode01"
},
..
3rd:
# Sequences collection
{
"_id": "A/Episode01/Sequence01",
"project": "A",
"episode": "Episode01",
"name": "Sequence01"
},
{
"_id": "A/Episode02/Sequence02",
"project": "A",
"episode": "Episode02",
"name": "Sequence02"
},
{
"_id": "B/Episode01/Sequence01",
"project": "B",
"episode": "Episode01",
"name": "Sequence01"
},
..
I want to use aggregate to query project A and get all of its corresponding episodes and sequences like this:
{
"_id": "A",
"episodes":
[
{
"_id": "A/Episode01",
"project": "A",
"name": "Episode01",
"sequences":
[
{
"_id": "A/Episode01/Sequence01",
"project": "A",
"episode": "Episode01",
"name": "Sequence01"
},
]
},
{
"_id": "A/Episode02",
"project": "A",
"name": "Episode02",
"sequences":
[
{
"_id": "A/Episode02/Sequence02",
"project": "A",
"episode": "Episode02",
"name": "Sequence02"
},
]
},
]
}
I can get as far as getting the proper episodes, but I'm not sure how to add an embed field for any matching sequences. Is it possible to do this all in a single pipeline query?
Right now my query is looking like this:
[
{"$match": {
"_id": "A"}
},
{"$lookup": {
"from": "episodes",
"localField": "_id",
"foreignField": "project",
"as": "episodes"}
},
{"$group": {
"_id": {
"_id": "$_id",
"episodes": "$episodes"}
}}
]
You can do like following
use $match to match the document
use uncorrelated queries to join two collection. But normal joining also possible as you have written. This is easier when we get some complex situations.
Mongo script is given below
[
{
"$match": {
"_id": "A"
}
},
{
$lookup: {
from: "Episodes",
let: {
id: "$_id"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$project",
"$$id"
]
}
}
},
{
$lookup: {
from: "Sequences",
let: {
epi: "$name"
},
pipeline: [
{
$match: {
$expr: {
$eq: [
"$episode",
"$$epi"
]
}
}
}
],
as: "sequences"
}
}
],
as: "episodes"
}
}
]
Working Mongo playground
Update 01
Using standard lookup
[
{
"$match": {
"_id": "A"
}
},
{
"$lookup": {
"from": "Episodes",
"localField": "_id",
"foreignField": "project",
"as": "episodes"
}
},
{
$unwind: "$episodes"
},
{
"$lookup": {
"from": "Sequences",
"localField": "episodes.name",
"foreignField": "episode",
"as": "episodes.sequences"
}
},
{
$group: {
_id: "$episodes._id",
episodes: {
$addToSet: "$episodes"
}
}
}
]
Working Mongo playground

MongoDB $lookup returns empty array [duplicate]

This question already has answers here:
Moongoose aggregate $match does not match id's
(5 answers)
Closed 4 years ago.
When i am trying to JOIN in mongo db the $lookup returns the empty array.
I have two collection one is user_information and another one is add_to_cart.In that i want to get add_to_cart details of user form add_to_cart collection using user_id in user_information.
add_to_cart collection:
[
{
"_id": {
"$id": "592ec12b744a12d014000031"
},
"order_id": "592ec125744a12d014000030",
"table_id": 1,
"category_name": "veg",
"food_id": "5923c8bc744a12441e000031",
"user_id": "592ec125744a12d01400002f",
"food_name": "Cream Of Mushroom Soup",
"food_per_price": "100",
"food_total_price": 100,
"food_qty": 1,
"active_status": 0,
"created_at": {
"sec": 1496236331,
"usec": 0
},
"updated_at": {
"sec": 1496236331,
"usec": 0
}
},
{
"_id": {
"$id": "592ec12e744a12d014000032"
},
"order_id": "592ec125744a12d014000030",
"table_id": 1,
"category_name": "veg",
"food_id": "5923c8cb744a12441e000033",
"user_id": "592ec125744a12d01400002f",
"food_name": "Cream Of Mushroom Soup",
"food_per_price": "100",
"food_total_price": 100,
"food_qty": 1,
"active_status": 0,
"created_at": {
"sec": 1496236334,
"usec": 0
},
"updated_at": {
"sec": 1496236334,
"usec": 0
}
}
]
user_information collection:
[
{
"_id": {
"$id": "592ec125744a12d01400002f"
},
"branch_id": 1,
"brand_id": 1,
"business_id": 1,
"table_id": 1,
"uid": "116907438816775509716",
"user_name": "dhamo dharan",
"user_email": "dhamursv#gmail.com",
"user_provider": "google",
"user_image": "https://lh5.googleusercontent.com/-Masl6FTlG_g/AAAAAAAAAAI/AAAAAAAAAEo/UV3oTjMnqzQ/s96-c/photo.jpg",
"active_status": 0,
"created_at": {
"sec": 1496236325,
"usec": 0
},
"updated_at": {
"sec": 1496236325,
"usec": 0
}
}
]
my database query
db.add_to_cart.aggregate([
{ "$match": { "user_id": "592ec125744a12d01400002f" } },
{ "$sort": { "created_at": -1 } },
{ "$limit": 20 },
{ "$lookup": {
"from": "user_information",
"localField": "user_id",
"foreignField": "_id",
"as": "userinfo"
} },
{ "$unwind": "$userinfo" },
{ "$project": {
"food_name": 1,
"food_qty": 1,
"userinfo.user_name": 1,
"userinfo.user_email": 1
} }
])
It will return empty result i don't know what went wrong.Thanks in advance!
In Simple Words - your match query is wrong .
Because "user_id": "592ec125744a12d01400002f" is a "string" , matching works fine with normal find query with string ObjectId
but when we talk about aggregate , you can not give direct string .. you always give mongoose.Types.ObjectId(userId) , where userId is string
var userId="592ec125744a12d01400002f";
db.add_to_cart.aggregate([
{ "$match": { "user_id": mongoose.Types.ObjectId(userId) } },
{ "$sort": { "created_at": -1 } },
{ "$limit": 20 },
{ "$lookup": {
"from": "user_information",
"localField": "user_id",
"foreignField": "_id",
"as": "userinfo"
} },
{ "$unwind": "$userinfo" },
{ "$project": {
"food_name": 1,
"food_qty": 1,
"userinfo.user_name": 1,
"userinfo.user_email": 1
} }
])