So basically I have a Patient schema, in which there are 2 fields:
patientSchema = {
//other_fields
current_facility: {
type: mongoose.Schema.Types.ObjectId,
ref: "Facility",
},
close_contact_list: {
type: [mongoose.Schema.Types.ObjectId],
ref: "Patient",
}
}
If i populate like this
Patient.find().populate({
path: "close_contact_list",
populate: {
path: "current_facility",
model: "Facility",
},
select: "id_number name dob status current_facility",
})
The result of 1 document would be:
{
//other_fields
"close_contact_list": [
{
"_id": "62e7e80bcdde7f149602775e",
"id_number": "201260388",
"name": "Tom",
"dob": "2003-01-01T00:00:00.000Z",
"status": "F1",
"current_facility": {
"location": {
"formattedAddress": "Phuong Phường 2, Quan Quận 2, TP Hồ Chí Minh",
"province": "Hồ Chí Minh",
"district": "Quận 2",
"ward": "Phường 2"
},
"_id": "62e7d60596997310f14e4bdb",
"name": "Thu Duc",
"capacity": 3000,
"current_count": 2,
"__v": 0
}
},
{
//similar_to_above
},
...
]
}
My question is how can i do the same thing but by using aggregate. I appreciate your help.
Try this:
Patient.aggregate([
{
"$lookup": {
"from": "Facility",
"localField": "_id",
"foreignField": "current_facility",
"as": "current_facility"
}
},
{
"$project": {
"id_number": 1,
"name": 1,
"dob": 1,
"status": 1,
"current_facility": 1
}
}
])
Related
What i want to do is find out which post i have reacted to and return true or false as below result i expect. i know about aggregation in mongodb but i don't know how it works yet. If anyone has study material about it, please comment. thank you.
// user model
{
"_id": "62d0d2e8306367e5162b9c4e",
"fullname": "string",
"username": "string",
"avatar": "string",
"bio": "string",
"tick": true,
"followings_count": 55,
"followers_count": 5,
"likes_count": 0,
"website_url": "",
"social_network": [],
"created_at": "2022-07-15T02:37:28.565Z",
"updated_at": "2022-08-23T08:23:16.611Z",
"__v": 0
}
// post model
{
"_id": "62f0ad6cca2731b7a851b5a5",
"contents": ":>>",
"media_url": "string",
"reaction_count": 1,
"view_count": 0,
"category_id": [],
"created_at": "2022-08-08T06:30:04.137Z",
"updated_at": "2022-08-24T04:10:33.944Z",
"__v": 0,
"comment_count": 9
}
// post_reaction model
{
"user_id": "62d0d2e8306367e5162b9c4e",
"post_id":"62f0ad6cca2731b7a851b5a5",
"type": "Like",
}
This is the result i expect:
{
"data": {
"user": {
"_id": "62d0d2e8306367e5162b9c4e",
...
},
"post": [
{
"_id": "62f0ad6cca2731b7a851b5a5",
...
"is_reaction": true(false)),
},
...
]
}
I found the way resolve this issues:
const result = await PostModel.aggregate([
{
$match: { user_id: ObjectUserId },
},
{
$lookup: {
from: 'post_reaction',
localField: '_id',
foreignField: 'post_id',
as: 'isReaction',
},
},
{
$project: {
_id: 1,
contents: 1,
media_url: 1,
reaction_count: 1,
view_count: 1,
category_id: 1,
created_at: 1,
updated_at: 1,
comment_count: 1,
isReaction: {
$filter: {
input: '$isReaction',
cond: {
$eq: ['$$this.user_id', ObjectUserId],
},
},
},
},
},
{ $sort: { _id: -1 } },
]);
This is my current query:
db.ministryteams.aggregate([
{
$addFields: {
"id_ministryTeam": { $toObjectId: "$_id" }
}
},
{
$lookup:
{
from: "profiles",
localField: "phone",
foreignField: "phone",
as: "profile"
},
},
{ $unwind: "$profile" },
{
$project: {
"profile._id": 1,
"profile.name": 1,
"profile.phone": 1,
"profile.type": 1,
"profile.contactAllowed": 1,
"profile.createAt": 1,
"id_ministryTeam": 1,
"_id": 0
}
}
])
And currently this query returns two profiles:
[{
"id_ministryTeam": "ObjectId(\"62a79c461df25412ae7ef2ff\")",
"profile": {
"_id": "ObjectId(\"62a798074e105c2b74fe6d81\")",
"name": "Informe seu nome aqui.",
"contactAllowed": true,
"type": "member",
"phone": "16900001111"
}
},
{
"id_ministryTeam": "ObjectId(\"62a79cf21df25412ae7ef311\")",
"profile": {
"_id": "ObjectId(\"62a79cf21df25412ae7ef30e\")",
"name": "Informe seu nome aqui.",
"contactAllowed": true,
"type": "member",
"phone": "16900001112"
}
}]
I would like to bring only one result, the profile._id: "62a798074e105c2b74fe6d81", I made several attempts with the match, but I couldn't get the expected result, if anyone can help me.
Try something like this
db.ministryteams.aggregate([
{
$addFields: {
"id_ministryTeam": { $toObjectId: "$_id" }
}
},
{
$lookup:
{
from: "profiles",
localField: "phone",
foreignField: "phone",
as: "profile"
},
},
{ $unwind: "$profile" },
{ $match: { "profile._id": mongoose.Types.ObjectId("your_ID_here") } },
{
$project: {
"profile._id": 1,
"profile.name": 1,
"profile.phone": 1,
"profile.type": 1,
"profile.contactAllowed": 1,
"profile.createAt": 1,
"id_ministryTeam": 1,
"_id": 0
}
}
])
I have 3 schema with a basic structure
meal: {
user: 'objectID',
createdAt: 'date
}
activity: {
user: 'objectID',
createdAt: 'date'
}
role: {
user: 'objectID',
createdAt: 'date'
}
I would like to get all documents from each schema belonging to a user and group them by dates. For example, a response of
history: [
{
date: 01-11-2021,
meal: [
...array of meal documents on 01-11-2021
],
activity: [
...array of meal documents on 01-11-2021
],
role: [
...array of meal documents on 01-11-2021
],
},
...next date
]
data
db={
"user": [
{
"_id": 1,
"name": "Sam"
}
],
"meal": [
{
"user": 1,
"content": "apple",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
},
{
"user": 1,
"content": "orange",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
},
{
"user": 1,
"content": "pie",
"createdAt": ISODate("2021-09-02T11:23:25.184Z")
}
],
"activity": [
{
"user": 1,
"content": "baseball",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
}
],
"role": [
{
"user": 1,
"content": "admin",
"createdAt": ISODate("2021-09-01T11:23:25.184Z")
}
]
}
aggreagte
db.user.aggregate([
{
"$match": {
_id: 1
}
},
{
"$lookup": {
"from": "meal",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "meal"
}
}
],
"as": "meal_docs"
}
},
{
"$lookup": {
"from": "activity",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "activity"
}
}
],
"as": "activity_docs"
}
},
{
"$lookup": {
"from": "role",
"localField": "_id",
"foreignField": "user",
"pipeline": [
{
"$set": {
"from": "role"
}
}
],
"as": "role_docs"
}
},
{
$project: {
user: "$name",
items: {
$concatArrays: [
"$activity_docs",
"$meal_docs",
"$role_docs"
]
}
}
},
{
"$unwind": "$items"
},
{
$project: {
createdAt: {
$dateTrunc: {
"date": "$items.createdAt",
"unit": "day"
}
},
content: "$items.content",
from: "$items.from"
}
},
{
"$group": {
"_id": {
"createdAt": "$createdAt",
"from": "$from"
},
"list": {
"$push": "$$ROOT.content"
}
}
},
{
"$group": {
"_id": "$_id.createdAt",
"documents": {
"$push": {
k: "$$ROOT._id.from",
v: "$$ROOT.list"
}
}
}
},
{
"$project": {
documents: {
$arrayToObject: "$documents"
}
}
},
{
"$group": {
"_id": 1,
"history": {
"$push": {
date: "$$ROOT._id",
activity: "$$ROOT.documents.activity",
meal: "$$ROOT.documents.meal",
role: "$$ROOT.documents.role"
}
}
}
}
])
mongoplayground
Is it possible to use MongoDB's aggregation framework to group channels using folder key and without joining documents?
[{key: 1, channels: {A: [], B: [], etc}}, {key: 2, channels: {A: [], B: [], etc}}]
I am trying to do using $unwind and then $group by folder name but it seems impossible.
Mongo Playground
Documents:
[
{
key: 1,
channels: [
{
"id": 1,
"name": "XXX",
"folder": "C"
},
{
"id": 2,
"name": "XXX",
"folder": "A"
},
{
"id": 3,
"name": "XXX",
"folder": "B"
},
{
"id": 4,
"name": "XXX",
"folder": "A"
},
{
"id": 5,
"name": "XXX",
"folder": "B"
},
{
"id": 6,
"name": "XXX",
"folder": "C"
}
]
},
{
key: 2,
channels: [
{
"id": 1,
"name": "XXX",
"folder": "D"
},
{
"id": 2,
"name": "XXX",
"folder": "B"
},
{
"id": 3,
"name": "XXX",
"folder": "A"
},
{
"id": 4,
"name": "XXX",
"folder": "C"
},
{
"id": 5,
"name": "XXX",
"folder": "A"
},
{
"id": 6,
"name": "XXX",
"folder": "D"
}
]
}
]
Expected Result:
[
{
key: 1,
channels: {
A: [{
"id": 2,
"name": "XXX"
},{
"id": 4,
"name": "XXX"
}],
B: [{
"id": 3,
"name": "XXX"
}, {
"id": 5,
"name": "XXX"
}],
C: [{
"id": 1,
"name": "XXX"
},{
"id": 6,
"name": "XXX"
}]
}
},
{
"key": 2,
"channels": ...
}
]
Thank you very much in advance.
$group by key and folder, construct channels array by providing required fields
$group by only key and construct the channels array in key-vlaue format
$arrayToObject convert above constructed channels to object
db.collection.aggregate([
{ $match: { key: { $in: [1, 2] } } },
{ $unwind: "$channels" },
{
$group: {
_id: {
id: "$key",
folder: "$channels.folder"
},
channels: {
$push: {
id: "$channels.id",
name: "$channels.name"
}
}
}
},
{
$group: {
_id: "$_id.id",
channels: {
$push: {
k: "$_id.folder",
v: "$channels"
}
}
}
},
{ $project: { channels: { $arrayToObject: "$channels" } } }
])
Playground
You just have to add one more $group stage followed by project stage which will alter the data as per requirement.
db.collection.aggregate([
{
$match: {
key: {
$in: [
1,
2
]
}
}
},
{
$unwind: "$channels"
},
{
$group: {
_id: {
key: "$key",
folder: "$channels.folder"
},
value: {
$push: "$channels",
},
"foldersRef": {
$push: "$channels.folder"
},
}
},
{
$group: {
_id: "$_id.key",
"channels": {
"$push": "$value"
},
},
},
{
"$project": {
"channels": {
"$map": {
"input": "$channels",
"as": "channel",
"in": {
"$arrayToObject": [
[
{
"v": {
"$map": {
"input": "$$channel",
"as": "subChannel",
"in": {
"id": "$$subChannel.id",
"name": "$$subChannel.name",
}
}
},
"k": {
"$arrayElemAt": [
"$$channel.folder",
0
]
},
}
]
],
},
}
},
},
},
])
Mongo Playground Sample Execution
What you have done is more appreciated. You might need two grop to easly preform the aggregations
$unwind to deconstruct the array
$group to group by key and foldername and second group to group by key only, but make the grp as key value pair which helps for $arrayToObject
$replaceRoot to make it to root with other fields _id ($mergeobjects)
$project for projection
Here is the code
db.collection.aggregate([
{ $unwind: "$channels" },
{
"$group": {
"_id": { key: "$key", fname: "$channels.folder" },
"channels": { "$push": "$channels" }
}
},
{
"$group": {
"_id": "$_id.key",
"grp": { "$push": { k: "$_id.fname", v: "$channels" } }
}
},
{ "$addFields": { "grp": { "$arrayToObject": "$grp" } } },
{
"$replaceRoot": {
"newRoot": { "$mergeObjects": [ "$grp", "$$ROOT" ] }
}
},
{
"$project": { grp: 0 }
}
])
Working Mongo playground
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
} }
])