Query MongoDb aggregate join two collections - mongodb

I need help for querying mongoDb
So I have two collections like
Collection A:
{someField: "123", anotherField: "456"},
{someField: "1234", anotherField: "4567"}
Collection B
{someField: "123", otherField: "789"}
with Query:
db.A.aggregate([
{
$lookup:
{
from: "B",
let: { someField: "$someField", otherField: "$otherField" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$someField", "$$someField" ] },
{ $eq: [ "$otherField", "789" ] }
]
}
}
},
],
as: "B"
}
}
])
I get all collection A, with B empty in {someField: "1234", anotherField: "4567"}
What I want to achieve is like:
{someField: "123", anotherField: "456", b: {someField: "123", otherField: "789"}}
Thank you in advance

you only need to declare $someField in the let section.
db.collectionA.aggregate([
{
$lookup: {
from: 'collectionB',
let: { some_field: '$someField' },
pipeline: [
{ $match: {
$expr: {
$and: [
{ $eq: [ "$someField", "$$some_field" ] },
{ $eq: [ "$otherField", "789" ] }
]
}
}
}
],
as: 'B'
}
},
{
$match: {
$expr: {
$gt: [ { $size: "$B" }, 0 ]
}
}
}
])
https://mongoplayground.net/p/RTiUMWl8QaX

This is how I removed the empty B array documents:
db.A.aggregate( [
{
$lookup: {
from: "B",
localField: "someField",
foreignField: "someField",
as: "B"
}
},
{
$addFields: {
B: {
$filter: {
input: "$B",
cond: {
$eq: [ "$$this.otherField", "789" ]
}
}
}
}
},
{
$match: {
$expr: {
$gt: [ { $size: "$B" }, 0 ]
}
}
}
] ).pretty()

Related

MongoDB aggregating data

when I am running code from Mongodb docs to use pipeline in the $lookup
I am getting an error that let is not supported. How to use let: { <var_1>: , …, <var_n>: } inside of $lookup.
Error:
Code:
db.orders.aggregate([
{
$lookup:
{
from: "warehouses",
let: { order_item: "$item", order_qty: "$ordered" },
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$stock_item", "$$order_item" ] },
{ $gte: [ "$instock", "$$order_qty" ] }
]
}
}
},
{ $project: { stock_item: 0, _id: 0 } }
],
as: "stockdata"
}
}
])

Mongo db - How to get two counts from same collection with a single lookup?

I have a working query below:
{
$lookup: {
from: "watchList",
as: "watchList",
let: {
postId: "$_id",
userId: userCurrent
},
pipeline: [
{
$match: {
$and: [
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
]
}
},
{
$count: "watchCount"
},
]
}
},
The above query gives me a count of two conditions combined in AND:
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
In addition, is it possible to get the count of ONLY { $expr: {$eq: ["$postId","$$postId"]} } without doing another lookup ?
So there will be two counts -
Count 1:
AND condition for
{ $expr: {$eq: ["$postId","$$postId"]} },
{ $expr: {$eq: ["$$userId", "$user"]} },
Count 2:
Single condition
{ $expr: {$eq: ["$postId","$$postId"]} }
You can do something like this,
$group first match count to firstCount and second match count to secondCount
{
$lookup: {
from: "watchList",
as: "watchList",
let: {
postId: "$_id",
userId: userCurrent
},
pipeline: [
{
$group: {
_id: null,
firstCount: {
$sum: {
$cond: [
{
$and: [
{ $eq: ["$postId", "$$postId"] },
{ $eq: ["$$userId", "$user"] }
]
},
1,
0
]
}
},
secondCount: {
$sum: {
$cond: [{ $eq: ["$postId", "$$postId"] }, 1, 0]
}
}
}
}
]
}
}

How to properly reference nested field within an array within an aggregate framework (MongoDB)?

I have a collection in the following format:
Collection name: COLL1
{
_id: "a",
list: [
{
_id: "a1",
ranking: 10
},
{
_id: "a2",
ranking: 30
}
...
]
}
{
_id: "b",
list: [
{
_id: "b1",
ranking: 10
},
{
_id: "b2",
ranking: 30
}
...
]
}
When I call: db.getCollection('COLL1').find({"_id": "a","list._id": "a1"}); I can see the results. However, if I call:
db.getCollection('COLL1').aggregate([
{ $match:
{ $expr:
{ $and:
[
{ $eq: ["$_id", "a"] },
{ $eq: ["$list._id", "a1"] }
]
}
}
}
])
Then nothing is returned. Does anyone know why? I think the issue is { $eq: ["$list._id", "a1"] } but I'm not sure what exactly happened here.
I'm trying to get the complete document:
{
_id: "a",
list: [
{
_id: "a1",
ranking: 10
},
{
_id: "a2",
ranking: 30
}
...
]
}
This is part of my aggregate syntax within a $lookup stage, so I have to use aggregate([]) instead of find(). What I'm actually trying to achieve is the following:
...previous stages
{
$lookup:{
from: "COLL1",
let: { local_id: "$_id" }, // this '$_id' is from another collection, not COLL1.
pipeline: [
{ $match:
{ $expr:
{ $and:
[
{ $eq: [ "$_id", "a"] },
{ $eq: [ "$$local_id", "$list._id" ] } // this is where I got in trouble.
]
}
}
}
],
as: "matched_result"
}
},
Thanks a lot!
If you don't need variables from previous pipeline stages, you can just use the same syntax as .find() inside $match
db.getCollection('COLL1').aggregate([
{ $match: { "_id": "a", "list._id": "a1" } }
])
Replacing the second $eq with $in will work just fine. :)
db.getCollection('COLL1').aggregate([
{ $match:
{ $expr:
{ $and:
[
{ $eq: ["$_id", "a"] },
{ $in: ["a1", "$list._id"] }
]
}
}
}
])

mongodb lookup using multiple fields not working

I am trying to get some other information from titleInfo collection using siteId of regCodes collection
I have two collections
regCodes
{
"siteId" : "123A",
"registration_code" : "ABC",
"used_flag" : true,
"Allowed_Use" : 1,
"Remaining_Use" : 0,
"BatchId" : "SNGL",
"CodeDuration" : 180
}
titleInfo
{
"title" : "Principles of Microeconomics",
"product_form_detail" : "EPUB",
"final_binding_description" : "Ebook",
"vitalsource_enabled" : false,
"reading_line" : "with InQuizitive and Smartwork5",
"volume" : "",
"protected_content" : {
"ebookSiteIds" : [
"123A"
],
"studySpaceSiteIds" : [],
"iqSiteIds" : []
}
}
below query not working, getting 'regcodeData' as empty array.
using mongodb version 3.6.18
db.getCollection('regCodes').aggregate([
{
$match: {
registration_code: 'ABC'
}
},
{
$lookup: {
from: "titleInfo",
let: {
regcode_siteId: "$siteId"
},
pipeline: [
{
$match: {
$expr: {
$or: [
{
$eq: [
"$protected_content.ebookSiteIds",
"$$regcode_siteId"
]
},
{
$eq: [
"$protected_content.studySpaceSiteIds",
"$$regcode_siteId"
]
},
{
$eq: [
"$protected_content.iqSiteIds",
"$$regcode_siteId"
]
}
]
}
}
}
],
as: "regcodeData"
}
}
])
below query is working as expected
db.getCollection('titleInfo').find({
$or: [
{
"protected_content.ebookSiteIds": "123A"
},
{
"protected_content.studySpaceSiteIds": "123A"
},
{
"protected_content.iqSiteIds": "123A"
}
]
})
You just need to unwind the arrays, by using $unwind operator with preserveNullAndEmptyArrays option set to true.
Updated Query:
db.regCodes.aggregate([
{
$match: {
registration_code: "ABC"
}
},
{
$lookup: {
from: "titleInfo",
let: {
regcode_siteId: "$siteId"
},
pipeline: [
{
$unwind: {
path: "$protected_content.ebookSiteIds",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$protected_content.studySpaceSiteIds",
preserveNullAndEmptyArrays: true
}
},
{
$unwind: {
path: "$protected_content.iqSiteIds",
preserveNullAndEmptyArrays: true
}
},
{
$match: {
$expr: {
$or: [
{
$eq: [
"$protected_content.ebookSiteIds",
"$$regcode_siteId"
]
},
{
$eq: [
"$protected_content.studySpaceSiteIds",
"$$regcode_siteId"
]
},
{
$eq: [
"$protected_content.iqSiteIds",
"$$regcode_siteId"
]
}
]
}
}
}
],
as: "regcodeData"
}
}
])
MongoPlayGroundLink
My bad trying to match array with string
Answer is as below
db.getCollection('regCodes').aggregate([
{
$match: {
registration_code: 'ABC'
}
},
{
$lookup: {
from: "titleInfo",
let: {
regcode_siteId: "$siteId"
},
pipeline: [
{
$match: {
$expr: {
$or: [
{
$in: [
"$$regcode_siteId",
"$protected_content.ebookSiteIds"
]
},
{
$in: [
"$$regcode_siteId",
"$protected_content.studySpaceSiteIds"
]
},
{
$in: [
"$$regcode_siteId",
"$protected_content.iqSiteIds"
]
}
]
}
}
}
],
as: "regcodeData"
}
}
])

how to use $groupby and transform distinct value mongodb

How to transform the data using $if $else groupby condition MongoDB?
This playground should return two object who belongs to text with "tester 2" and "tester 3" also if I have multiple object in history collection it should also check with last object not will all object how it is possible
So condition should say if history's date is $gt then main collection should return nothing else return the matched criteria data.
db.main.aggregate([
{
$lookup: {
from: "history",
localField: "history_id",
foreignField: "history_id",
as: "History"
}
},
{
$unwind: "$History"
},
{
"$match": {
$expr: {
$cond: {
if: {
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
then: {
$and: [
{
$gt: [
"$date",
"$History.date"
]
},
{
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
}
]
},
else: {}
}
}
}
}
])
MongoPlayground
If I understand you correctly, it is what you are trying to do:
db.main.aggregate([
{
$lookup: {
from: "history",
let: {
main_history_id: "$history_id",
main_user_id: { $toString: "$sender_id" }
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$history_id",
"$$main_history_id"
]
},
{
$eq: [
"$user_id",
"$$main_user_id"
]
}
]
}
}
}
],
as: "History"
}
},
{
$unwind: {
path: "$History",
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
_id: 1,
"History.history_id": 1,
"History.date": 1
}
},
{
$group: {
_id: "$_id",
data: { $last: "$$ROOT" },
History: { $last: "$History" }
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$data",
{ History: "$History" }
]
}
}
},
{
"$match": {
$expr: {
$or: [
{
$eq: [
{ $type: "$History.date" },
"missing"
]
},
{
$ne: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
{
$and: [
{
$eq: [
"5e4e74eb380054797d9db623",
"$History.user_id"
]
},
{
$gte: [
"$date",
"$History.date"
]
}
]
}
]
}
}
}
])
MongoPlayground