Mongodb aggregate use match with lookup - node.js

So I have this code here:
Achievement.aggregate([
{"$match": {}},
{
$lookup: {
from: "achievementcompleteds", // collection name in db
localField: "_id",
foreignField: "achievement_id",
as: "completed"
}
}]).then((results) => {
So what it does it shows the ahcievements to user and also shows if its completed next to the achievement. But the problem is that if one user completes achievement then for every user it is shown that it is completed. So I need to get achievementcompleteds by user_id somehow.
achievemets: _id title etc
achievementcompleteds: _id achievement_id user_id
EDIT
Okay so this code:
Achievement.aggregate([
{
"$lookup": {
"from": "achievementcompleteds", // collection name in db
"localField": "_id",
"foreignField": "achievement_id",
"as": "completeds"
}},
{ "$match": {"completeds.user_id": user._id}}
]).then((results) => {
returns me only achievements for user that are completed. So the problem is that it doest me return all achievements list right now.

Related

Query collection with array of values from another collection - MongoDB

Let's say I want to make a sticker albums app, where users can "buy" albums and stickers, etc.
So the relation between users and albums would be many-to-many.
If my user collection looks like this
{"_id":{"$oid":"61a04f49909f8e972f5722f1"},"email":"1234#gmail.com","password":"$2b$10$g06lbwH4jNd4O9R/dbaqnus10iy1uhGeroge.bXkUeBxTSaVkR75a","albums_ids":["61a45889f3bedd5c1b7a9db4","61a45969f3bedd5c1b7a9db6"]}
with the albums_ids array referencing the objectIds of the "albums" collection
{"_id":{"$oid":"61a45889f3bedd5c1b7a9db4"},"name":"Brasil 2014"}
How can I create a query to get all the albums the user has in it's albums_ids array?
You will have to unwind the albums_ids first and do a lookup on the albums collection. After which do a unwind again and group them all up by user id and push/addToSet the albums into an array.
MongoDB Playground
db.users.aggregate([
{
$unwind: "$albums_ids"
},
{
"$lookup": {
"from": "albums",
"localField": "albums_ids",
"foreignField": "_id.oid",
"as": "albums"
}
},
{
$unwind: "$albums"
},
{
$group: {
_id: "$_id.oid",
albums: {
"$push": "$albums"
}
}
}
])
There might be a better query, my mongo is a bit rusty.

How to do join two collections in mongoose

I am actually struggling with this from a long time.
I have a sql query
select * from posts where post_uploader='$user_id' or post_uploader in(select follow_user_id from follow where follow_follower_id='$user_id') order by updated_at
Can anyone tell me how to do the same thing with mongo db?
I tried to do this but I am getting error in LocalField. It requires string where I am passing object.
postModel.aggregate([{
$lookup: {
from: "follow",
localField: req.user.id,
foreignField: "follow_follower_id",
as: "follow"
}
}])
I guess foreignField's correct Field is "_id"
postModel.aggregate([
{
$lookup:
{
from: "follow",
localField: req.user.id,
foreignField: "_id",
as: "follow"
}
}])
but your question don't have enough information

MongoDB lookup by _id with let does not work

I'm using a aggregate query to retrieve data from multiple collections, however there is a strange behavior that I dont seem to understand.
I need to lookup throw two collections, thus the lookup inside the pipeline. And also use the _id from the collection I'm making the aggregation(campaignadgroups) to match on the second nested collection (broadcastplans)
This is my query:
db.getCollection('campaignadgroups').aggregate([
{
$match: { "campaign_id": ObjectId("5fc8f7125148d7d0a19dcbcb")} // hardcoded just for tests
},
{
$lookup: {
from: "broadcastreports",
let: {campaignadgroupid: "$_id"},
pipeline: [
{
$match: {"reported_at": { $gte:ISODate("2020-12-01T15:56:58.743Z"), $lte: ISODate("2020-12-03T15:56:58.743Z")} }
},
{
$lookup: {
from: "broadcastplans",
localField: "broadcast_plan_id",
foreignField: "_id",
as: "broadcastplan"
}
},
{$unwind: "$broadcastplan"},
{
$match: { "broadcastplan.campaign_ad_group_id": {$eq: "$$campaignadgroupid"} // The problem happens here
}
}
],
as: "report"
}
},
])
The issue is that by matching with $$campaignadgroupid the report documents is empty.
However, if I replace the variable with the hardcoded id like ObjectId("5fc8f7275148d7d0a19dcbcc") I get the documents that I pretend.
For reference I'm debugging this issue on Robot3T so I can then translate to mongoose later.
I tried already to use $toObjectId however the _ids are not strings but ObjectIds already.
Thank you very much
Ok this is why I love and hate to code. After 3h debugging after asking here I immediately discovered the issue... I just needed to change from
$match: { "broadcastplan.campaign_ad_group_id": {$eq: "$$campaignadgroupid"}
to
$match: { $expr: { $eq: ["$broadcastplan.campaign_ad_group_id", "$$campaignadgroupid"]}

How to use $lookup and $match against it in MongoDB aggregation?

I am having trouble with aggregation in Mongodb. I have a model User and UserExtra with extra details about the user. I need to do a $lookup to connect UserExtra to User output. But want to be able to filter results, based on age, gender and city, which are part of UserExtra. My current query is as follows, and it should return results but returs empty array.
const match = {
'userExtra.age': {
$gt: dateTo.toISOString(),
$lt: dateFrom.toISOString()
},
'userExtra.gender': gender
}
if (city) match['userExtra.city'] = city;
const users = await User.aggregate([
{
$lookup: {
from: 'user_extra',
localField: 'userExtra',
foreignField: '_id',
as: 'userExtra'
}
},
{
$match: match
},
{
$unwind: "$userExtra"
}
]);
res.send(users);
You have to unwind the lookup result first, then match pipeline.
let pipelineQuery = [
{
$lookup: {
from: 'user_extra',
localField: 'userExtra',
foreignField: '_id',
as: 'userExtra'
}
},
{
$unwind: "$userExtra"
},
{
$match: match
},
]
Hey guys I figured it out. I was using toIsoString() method, which turns the date into a string. All I did was remove the method and just passed the dateTo and dateFrom dates and now it works.
I would suggest testing each part of query one by one..First just run the lookup part in aggregate to see what the result looks like.After that run match.and subsequently add unwind.

How to query multiple MongoDB collections and NodeJS?

I have three collections in MongoDB.
In Drug JSON, using MEDID get its respective CMIDs from Composition JSON. Using that CMIDs get its respective chemical Names from the Chemicals JSON, then stores in one array with their medid, cmid and its name.
I'm using NodeJS. Please help me, thanks in advance.
DRUG collection
{
"MEDID":"AAA001-01",
"BRANDNAME":"TASULIN D",
"MEDTYPECODE":"CAP",
"DOSE":"",
"DOSEUNIT":"",
"CHEMICAL1":"TAMSULSIN HYDROCHLORIDE",
"CHEMICAL2":"DUTASTERIDE",
"CHEMICAL3":"",
"CHEMICAL4":"",
"CHEMICAL5":"",
"CHEMICAL6":"",
"CHEMICAL7":"",
"CHEMICAL8":"",
"CHEMICAL9":"",
"CHEMICAL10":"",
"CHEMICAL11":"",
"SPECIALITY":"GEN",
"MANUFACTURER":"IPCA",
"MFTID":"xyz123"
}
Compostion Collection
{"MEDID":"AAA001-01","CMID":"ABC001"},
{"MEDID":"AAA001-01","CMID":"ABC002"}
Chemical Collection
{"CMID":"ABC001","Name":"TAMSULSIN HYDROCHLORIDE"},
{"CMID":"ABC002","Name":"DUTASTERIDE"},
db.drug.aggregate([
{
$lookup:
{
from: "composition",
localField: "medid",
foreignField: "medid",
as: "composition"
}
},
$lookup:
{
from: "chemical",
localField: "composition.cmid",
foreignField: "cmid",
as: "chemical"
}
},
$group: {
_id: "$medid",
cmid: { $first: "$composition.cmid" },
name: { $first: "$chemical.name" }
]);

Resources