when i do a lookup in mongodb i enter an as field and the data is loaded into this field. But if I have an array of objects and one of the fields is a REF field then I always have the problem that the data from the lookup is always loaded into a separate field and I cannot find it with the array. How can I do a lookup that loads the data directly into the array element.
for example
i have a organisation with an array of users and there status and role in the organisation
{
_id: "60cc87da3a530000173f6d33",
"baseData": {
"name": "Organisation 1",
"email": "org#gmail.com",
"image": "",
"description": "desc",
"users": [
{
userID: "60cc87803a530000173f6d2d",
userStatus: "active" ,
userOrgRole: "Admin"
},
{
userID: "60cc87803a530000173f9h4u",
userStatus: "active" ,
userOrgRole: "User"
}
]
}
}
when i made a lookup an define the as field as baseData.users the user array are overwirte with the user data. But how i can add the data to each users array.
for example this is the result i need
{
_id: "60cc87da3a530000173f6d33",
"baseData": {
"name": "Organisation 1",
"email": "org#gmail.com",
"image": "",
"description": "desc",
"users": [
{
userID: "60cc87803a530000173f6d2d",
userStatus: "active" ,
userOrgRole: "Admin"
// userdata data from lookup for each array
},
{
userID: "60cc87803a530000173f9h4u",
userStatus: "active" ,
userOrgRole: "User"
// userdata data from lookup for each array
}
]
}
Try this way, add these stages to aggregation pipeline. It will help to add user details..
{
$unwind: {
path: "$baseData.users",
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: "users", // replace with your collection name
localField: "baseData.users.userID",
foreignField: "_id",
as: "baseData.users",
},
},
{
$group: {
_id: "$_id",
baseData: {
$push: "$baseData",
},
},
},
Related
How can make I lookup on in with productId and categoryId.
Below is the sample of JSON
"data": {
"status": 1,
"offerId": "634017ad34c7b3545bd47681",
"offerType": "buyOneGetOne",
"categoryId": [
"62de9b22dcafd44290ab03c1",
"62dfe695ec4d69cfeab0265d"
],
"productId": [
"633170230e88e2d859d15ee6",
"62de9d102b2b72f80eda7585",
"62de9d1e2b2b72f80eda7588"
],
"title": "Buy One Get One Deal ",
"description": "buy one get more",
"amountType": "amount",
"amount": 12341,
"startDate": "2022-10-04T06:43:39.000Z",
"endDate": "2022-10-08T06:43:39.000Z"
}
I'm going to assume that you are using ObjectId as _id in your categories and products collection. If I understood your question your document as the following minimal structure:
_id: '1',
data: {
...
}
So, you are looking for something like:
db.nameOfYourCollectionWithData.aggregate([{
$addFields: {
'data.categoryId': {
$map: {
input: '$data.categoryId',
'in': {
$toObjectId: '$$this'
}
}
},
'data.productId': {
$map: {
input: '$data.productId',
'in': {
$toObjectId: '$$this'
}
}
}
}
}, {
$lookup: {
from: 'categories',
localField: 'data.categoryId',
foreignField: '_id',
as: 'data.categoryId'
}
}, {
$lookup: {
from: 'products',
localField: 'data.productId',
foreignField: '_id',
as: 'data.productId'
}
}])
First, you have to convert your array ids into ObjectId. After do this, you can perform the lookup stages directly. If your document is 'data', just remove any reference to data in the aggregate pipeline.
If your _id in categories and products are string instead of ObjectId, just remove the $addFields stage, because is no longer neccessary.
I'm trying to get an element value based on a result _id in an aggregation.
This is the aggregation:
$project: {
_id: 0,
brand: "$_id",
"options": {
$mergeObjects: "$ram"
},
sum: {
$add: [
"$sm",
1
]
}
}
And I want brand to get the name from other collection named "brands" which looks like this
[
{
"_id": ObjectId("617b0dbacda6cbd1a0403f68"),
"SerialNumber": "45454234324",
"name": "hp"
},
{
"_id": ObjectId("617b0dbacda6cbd1a0403f69"),
"SerialNumber": "azazz5245454az",
"name": "asus"
}]
What I want to get is the name of brand using using its _id based on the result _id.
Using SQL its something like this:
Get brands.name where _id=brands._id
i managed to do it using $lookup
{
$lookup:
{
from: "brands",
localField: "brand",
foreignField: "_id",
as: "brand"
}
},
{
$set: {
brand: "$brand.brand"
}
},
I need to replace members array data with new array of objects mems given below.
{
"name": "Test Group",
"members": [{
'userId': {
$oid: 'fjkfkffy'
},
name: 'Himanshu'
}],
"athletes": [],
"leads": []
}
Here I want to replace members array of object with new array of objects. I basically need to overwrite that members array. I've been trying to do something like this below, but I got an error. Can anyone please help me out?
const mems = [{
"user": {
"$oid": "6093a4a709cc0b000d31ber8",
},
"role": "manager"
},
{
"user": {
"$oid": "60a3aea6ecbf4398f01aa598"
},
"role": "user"
}
];
entities.findOneAndUpdate({
_id: ObjectID(entityID),
"groups._id": ObjectID(groupID)
}, {
$set: {
'groups.$.name': name,
'groups.$.members': mems
}
}, {
'new': true
});
I have a query looking like this:
const articles = await Article.find(query)
.populate({
path: 'votedUsers', // array of users id
select: 'title name username',
options: {
limit: 3,
sort: { createdAt: -1 },
},
})
.exec()
Result:
[
{
title: 'Article title',
votedUsers: [,,], // array of populated users with limit of 3
totalCountVoted: 200 // need to add this field
}
]
I want to find articles and populate votedUsers property but with limit to 3 users, but at the same time
I need to know how many ids were in votedUsers property.
For example it can be 200 users that voted on that article, but I just need to know the number and populate only 3 of them.
You can try the following aggregation using the match, lookup, project stages, and slice and size operators:
(Please note that the "users" value in lookup from must be the physical collection name.)
app.get("/article", async (req, res) => {
const data = await Article.aggregate([
{
$match: {
category: "Category1"
}
},
{
$lookup: {
from: "users",
localField: "votedUsers",
foreignField: "_id",
as: "users"
}
},
{
$project: {
title: 1,
votedUsers: { $slice: ["$users", 3] },
totalCountVoted: { $size: "$users" }
}
}
]);
res.send(data);
});
This will give you a result like this:
[
{
"_id": "5dded78f8f30c402b0fac309",
"title": "Article1",
"votedUsers": [
{
"_id": "5dded60a84523642bc27f511",
"__v": 0,
"name": "User1"
},
{
"_id": "5dded61384523642bc27f512",
"__v": 0,
"name": "User2"
},
{
"_id": "5dded61b84523642bc27f513",
"__v": 0,
"name": "User3"
}
],
"totalCountVoted": 8
},
{
"_id": "5dded7c18f30c402b0fac30a",
"title": "Article2",
"votedUsers": [
{
"_id": "5dded61b84523642bc27f513",
"__v": 0,
"name": "User3"
},
{
"_id": "5dded63c84523642bc27f514",
"__v": 0,
"name": "User4"
},
{
"_id": "5dded64484523642bc27f515",
"__v": 0,
"name": "User5"
}
],
"totalCountVoted": 8
}
]
Playground
I have 2 collections in my database. One is called User
{
_id: storeUserId,
name: ...,
etc
}
the other one called Following
{
userId: ...,
followingUserId: ...
}
the userId is the current user id and the followingUserId is the id that current user wants to follow.
For example, in User collection I have:
{
_id: userIdOne,
etc
},
{
_id: userIdTwo,
etc
}
and in Following collection I have:
{
userId: userIdThousand,
followingUserId: userIdTwo
}
When I run find query
db.bios.find();
I get
{
"_id": userIdTwo,
"username": "random27005688"
},
{
"_id": userIdThree
"username": "random232111"
},
{
"_id": userIdOne
"username": "random2702"
}
]
The result is what I want but I want to add a 'isFollowed' field to each result item to check following status. I have a user id let say: 'userIdThousand' which I want to use it to check against each result item based on my Following collection. E.g,
check if userIdThousand is following userIdOne
check if userIdThousand is following userIdTwo, etc.
Below is my expected result. Thanks!
[
{
_id: userIdTwo,
"username": "random27005688",
"isFollowed": true
},
{
"_id": userIdThree
"username": "random232111",
"isFollowed": false
},
{
"_id": userIdOne
"username": "random2702",
"isFollowed": false
},
]
You need $lookup to get the data from second collection matching by followingUserId then you can use $filter to get only followers with particular _id and check if new array has any elements (using $size) which means that user is followed by other user:
db.User.aggregate([
{
$match: {
_id: { $ne: "userIdOne" }
}
},
{
$lookup: {
from: "Following",
localField: "_id",
foreignField: "followingUserId",
as: "followers"
}
},
{
$addFields: {
followers: {
$filter: { input: "$followers", as: "follower", cond: { $eq: [ "$$follower._id", "userIdOne" ] } }
}
}
},
{
$project: {
_id: 1,
username: 1,
isFollowed: { $gt: [ { $size: "$followers" }, 0 ] }
}
}
])
maybe you could split it into two step.
1. query User and get the result
for example, you get a user.
{
_id: userIdTwo,
"username": "random27005688",
}
2. query Following and get if the user has been followed.
such as
has_followed=db.Following.find({"userId":userIdTwo}).count()
not the best solution but it might help u.