Aggregate not working as expected in mongoose - mongodb

Here's a lookup query that i'm using
{
$lookup: {
from: 'weeks',
localField: 'weeks',
foreignField: '_id',
as: 'weeks'
}
}
Result with this query
"weeks": [
{
"_id": "619e87d7b1bd6501c7aae286",
"name": "week-1",
"description": "Commodo in o.",
"course": "619e87d7b1bd6501c7aae281",
"days": [
"619e87dab1bd6501c7aae2a8",
"619e87dab1bd6501c7aae2a9",
"619e87dab1bd6501c7aae2aa",
"619e87dab1bd6501c7aae2ab",
"619e87dab1bd6501c7aae2ac",
"619e87dab1bd6501c7aae2ad"
],
"isCopy": false,
"__v": 0
},
{
"_id": "619e87d7b1bd6501c7aae287",
"name": "week-2",
"description": "Irure e.",
"course": "619e87d7b1bd6501c7aae281",
"days": [
"619e87dab1bd6501c7aae2db",
"619e87dab1bd6501c7aae2dc",
"619e87dab1bd6501c7aae2dd",
"619e87dab1bd6501c7aae2de",
"619e87dab1bd6501c7aae2df",
"619e87dab1bd6501c7aae2e0"
],
"isCopy": false,
"__v": 0
},]
In the above lookup localField weeks is an array of object Id's.
When i execute this code it works as expected, but i want to use the same functionality with pipeline.
Here's the code i wrote
{
$lookup: {
from: "weeks",
let: { wks: "$weeks" },
pipeline: [
{
$match: {
_id: {
$in: ["$$wks"]
}
}
}
],
as: "weeks"
}
}
Result with this query `weeks:[]`
When i run this, i don't get anything in output, the reason for that in my opinion is that weeks array is being interpreted as a string instead of object id.
How do i fix it now ...

Is this what you need ? Check my mongoplayground below, if not, make your own sample data and share a new link with me.
db.collection.aggregate([
{
$lookup: {
from: "weeks",
let: {
wks: "$weeks"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$_id",
"$$wks"
]
}
}
}
],
as: "weeks"
}
}
])
mongoplayground

Related

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.

How to Group By and Count values inside multi layered array in mongoDB?

I have very complicated Document of MongoDB
For example: Order Document >>>
{
"_id": "62cdbae0421b250009acc329",
"cartitems": "62cdbaaf74c9c80009f5a4b2",
},
{
"_id": "62d27e192b254600099ae680",
"cartitems": "62d27d9d91568c0009866d23",
}
and cart Document >>>
{
"_id": "62cdbaaf74c9c80009f5a4b2",
"cartItems": [
{
"productCode": [
"NCK-1"
],
"Price": "56",
},
{
"productCode": [
"NCK-2"
],
"Price": "56",
}
],
},
{
"_id": "62d27d9d91568c0009866d23",
"cartItems": [
{
"productCode": [
"NCK-3"
],
"Price": "56",
},
{
"productCode": [
"NCK-1"
],
"Price": "56",
}
],
},
I want to join Order Document Order.cartitems with Cart._id and groupby ProductCode and Count Product Code and Sum Price i.e In total the result must look like
NCK-1 112
NCK-2 56
NCK-3 56
I tried the following code >>>
Order.aggregate([
{
$lookup: {
from: Cart.collection.name,
localField: 'cartitems',
foreignField: '_id',
as: 'cartitems',
},
},
{ $unwind: '$cartitems' },
{
$group: {
_id: '$cartitems.cartItems.productCode',
count: { $sum: '$cartitems.cartItems.Price' },
},
},
]);
I could not find the solution please guide me in solving this.
$lookup
$unwind
$unwind - Deconstruct the cartitems.cartItems array into multiple documents.
$group - Since there is only one item in cartitems.cartItems.productCode, can consider using $first to take the first value of the array. And you need to cast cartitems.cartItems.Price to number type before sum.
db.order.aggregate([
{
$lookup: {
from: "cart",
localField: "cartitems",
foreignField: "_id",
as: "cartitems"
}
},
{
$unwind: "$cartitems"
},
{
$unwind: "$cartitems.cartItems"
},
{
$group: {
_id: {
$first: "$cartitems.cartItems.productCode"
},
count: {
$sum: {
$toInt: "$cartitems.cartItems.Price"
}
}
}
}
])
Sample Mongo Playground

MongoDB aggregate $lookup with _ID's from array

I have two collections in MongoDB: "carts" and another "products"
Carts:
[{
"_id": {
"$oid": "62af0fefebc0b42a875c7df1"
},
"uuid": "6ca05ae0-522a-4db3-b380-2d2330ee1e27",
"cartitems": [
"62a0b24680cc2891148daf7b",
"62a7339d91d01868921afa0a",
"62a72f7191d01868921afa08",
"62a7330291d01868921afa09"
],
"created": "2022-06-19T14:00:47.846958537+02:00[Europe/Brussels]",
"lastupdate": "2022-06-19T14:01:06.15165564+02:00[Europe/Brussels]"
},
{...},
{...}]
products:
[{
"_id": {
"$oid": "62a0b24680cc2891148daf7b"
},
"name": "Product1",
"created": "2022-06-11T09:41:54.461308647+02:00[Europe/Brussels]",
"category": "Workshops",
"pricein": "28900",
"lastupdate": "2022-06-17T16:09:53.385655474+02:00[Europe/Brussels]"
},
{...},
{...}]
I would like to use Aggregate:
db.carts.aggregate([
{ $match: { uuid: "6ca05ae0-522a-4db3-b380-2d2330ee1e27" } },
{
$lookup: {
from: "products",
localField: "cartitems",
foreignField: "_id",
as: "output"
}
}
])
This is not working because localField: "cartitems" should be converted:
"$addFields": {
"convertedIdStr": {
"$toString": "$cartitems"
}
But I don't manage to convert because cartitems is an array.
Any help would be great, Thanks a lot!
Use $lookup with pipeline. In $lookup pipeline stage, add $match stage by filtering the (converted to string) product's _id is in cartitems (array) variable.
db.carts.aggregate([
{
$match: {
uuid: "6ca05ae0-522a-4db3-b380-2d2330ee1e27"
}
},
{
$lookup: {
from: "products",
let: {
cartitems: "$cartitems"
},
pipeline: [
{
$match: {
$expr: {
$in: [
{
$toString: "$_id"
},
"$$cartitems"
]
}
}
}
],
as: "output"
}
}
])
Sample Mongo Playground

Request to check all array elements

I have a problem with MongoDB syntax.
I have two documents:
alley(the "tree" field is the ID of the tree):
{
"_id": {"$oid": "62572d82cc40164fef7f1a56"},
"name": "good alley",
"tree": [
{"$oid": "626976eb4b93122bc617d701"},
{"$oid": "626976eb4b93122bc617d702"}
]
},
.......
tree:
{
"_id": {"$oid": "626976eb4b93122bc617d701"},
"dateInstall": {"$date": "2021-02-27T00:00:00.000Z"},
"species": [
{"$oid": "62585a63edfc726a4ff24fb8"}
]
},
.......
I need to write a query "an alley where trees were not planted last year"
My Code
db.alley.aggregate([
{
$lookup: {
from: "tree",
localField: "tree",
foreignField: "_id",
as: "tree"
}
},
{
$match: {{$not:{$and:[
{"tree.dateInstall": {$gt: new ISODate("2020-12-31")}},
{"tree.dateInstall": {$lt: new ISODate("2022-01-01")}}
]
}}}
}
]);
You should first $unwind trees in alleys so you can properly $lookup the trees in tree collection. Use pipeline inside lookup to query only trees planted last year. Finally $group trees into alleys again and use $match to filter out those alleys without trees.
db.getCollection("alley").aggregate([
{
$unwind: "$tree",
},
{
$lookup: {
from: "tree",
let: { tree: "$tree" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: [ "$$tree", "$_id" ] },
{ $gt: [ "$dateInstall", new ISODate("2020-12-31") ] },
{ $lt: [ "$dateInstall", new ISODate("2022-01-01") ] },
]
}
}
}
],
localField: "tree",
foreignField: "_id",
as: "tree"
}
},
{
$group: {
_id: { id: "$_id", name: "$name" },
trees: { $addToSet: { $first: "$tree" } }
}
},
{
$match: {
trees: { $size: 0 }
}
}
])

How to perform lookup in aggregation when foreignField is in array?

I have two collections:
// users
{
_id: "5cc7c8773861275845167f7a",
name: "John",
accounts: [
{
"_id": "5cc7c8773861275845167f76",
"name": "Name1",
},
{
"_id": "5cc7c8773861275845167f77",
"name": "Name2",
}
]
}
// transactions
{
"_id": "5cc7c8773861275845167f75",
"_account": "5cc7c8773861275845167f76",
}
Using lookup I want to populate _account field in transactions collection with respective element from users.accounts array.
So, I want the final result as:
{
"_id": "5cc7c8773861275845167f75",
"_account": {
"_id": "5cc7c8773861275845167f76",
"name": "Name1",
},
}
I have already tried using this code:
db.transactions.aggregate([
{
$lookup:
{
from: "users.accounts",
localField: "_account",
foreignField: "_id",
as: "account"
}
}
])
In the result account array comes as empty.
What is the correct way to do it ?
You can use below aggregation with mongodb 3.6 and above
db.transactions.aggregate([
{ "$lookup": {
"from": "users",
"let": { "account": "$_account" },
"pipeline": [
{ "$match": { "$expr": { "$in": ["$$account", "$accounts._id"] } } },
{ "$unwind": "$accounts" },
{ "$match": { "$expr": { "$eq": ["$$account", "$accounts._id"] } } }
],
"as": "_account"
}},
{ '$unwind': '$_account' }
])
Try with this
I think case 1 is better.
1)-
db.getCollection('transactions').aggregate([
{
$lookup:{
from:"user",
localField:"_account",
foreignField:"accounts._id",
as:"trans"
}
},
{
$unwind:{
path:"$trans",
preserveNullAndEmptyArrays:true
}
},
{
$unwind:{
path:"$trans.accounts",
preserveNullAndEmptyArrays:true
}
},
{$match: {$expr: {$eq: ["$trans.accounts._id", "$_account"]}}},
{$project:{
_id:"$_id",
_account:"$trans.accounts"
}}
])
2)-
db.getCollection('users').aggregate([
{
$unwind:{
path:"$accounts",
preserveNullAndEmptyArrays:true
}
},
{
$lookup:
{
from: "transactions",
localField: "accounts._id",
foreignField: "_account",
as: "trans"
}
},
{$unwind:"$trans"},
{
$project:{
_id:"$trans._id",
_account:"$accounts"
}
}
])