How to inner join in mongodb. (aggregation) - mongodb

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 } },
]);

Related

MongoDB, return selected fields from document with aggregation operations

With given query I also want to return productId.
I have collection comments that contains documents with data about productId and comments for given product
Example document in this collection:
{
"_id": {
"$oid": "635ee64f55460d1796447662"
},
"productId": "63413800d36ed477adc763d0",
"__v": 0,
"comments": [
{
"userId": "",
"userName": "test",
"date": "2022.12.18.21.51.36",
"confirmed": false,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 6,
"description": "testtesttest"
},
"image": {
"added": false,
"images": []
},
"_id": {
"$oid": "639f7d58b6206a863c4a7aba"
},
"usersWhoLiked": []
},
{
"userId": "",
"userName": "test",
"date": "2022.12.18.21.52.19",
"confirmed": false,
"likes": {
"up": 0,
"down": 0
},
"content": {
"rating": 6,
"description": "testtesttest"
},
"image": {
"added": true,
"images": [
"comments/63413800d36ed477adc763d0/639f7d83b6206a863c4a7ad6/dell.jpg"
]
},
"_id": {
"$oid": "639f7d83b6206a863c4a7ad6"
},
"usersWhoLiked": []
}
]
}
My exmaple query:
db.comments.aggregate([{$match: {"comments._id": {$in: [ObjectId('630b7868f51e10876223b4aa'), ObjectId('630bd277f919a9e9c0e7a559')]}}},
{$project: {comment: {$filter: {input: "$comments", as: "comment", cond: {$in: ["$$comment._id", [ObjectId("630b7868f51e10876223b4aa"), ObjectId("630bd277f919a9e9c0e7a559")]]}}}}}])
With this query I get the result :
{ _id: ObjectId("630b7868f51e10876223b4a6"),
comment:
[ { userId: '62f29c2c324f4778dff443f6',
userName: 'User',
date: '2022.08.19',
confirmed: false,
likes: { up: 3, down: 0 },
content: { rating: 4, description: 'Super laptop <3' },
_id: ObjectId("630b7868f51e10876223b4aa"),
usersWhoLiked:
[ { userId: '62f29c2c324f4778dff443f6',
likeUp: true,
_id: ObjectId("630d2b0494370efb37107983") },
{ userId: '6322434f2b5bbac87f0e7aba',
likeUp: true,
_id: ObjectId("632243702b5bbac87f0e7afa") },
{ userId: '62f2991e324f4778dff443d4',
likeUp: true,
_id: ObjectId("63af4d77c8991b74d6986995") } ] } ] }
{ _id: ObjectId("630bd277f919a9e9c0e7a555"),
comment:
[ { userId: '62f29c2c324f4778dff443f6',
userName: 'User',
date: '2022.08.28',
confirmed: false,
likes: { up: 1, down: 1 },
content:
{ rating: 6,
description: 'Laptop posiada przyjemna klawiature, nie grzeje się. Do codziennego grania wystarczy.' },
_id: ObjectId("630bd277f919a9e9c0e7a559"),
usersWhoLiked:
[ { userId: '62f29c2c324f4778dff443f6',
likeUp: true,
_id: ObjectId("630d2dfc94370efb37107991") },
{ userId: '62fa2549f029348f75bc9c81',
likeUp: false,
_id: ObjectId("631241fe755c641525dc9cfa") } ] } ] }
As you see in the result, the productId is missing.
I was trying to rebuild query with #group operator but still with out effect...
So my questsion is:
How shall I rewrite that query to get the same result but with productId in it for each returned comment
This is how $project works, if a field is not specified will not be output.
So just add productId: 1 into the $project stage and it will be shown.
Check this example.

How to find particular data with date array list in mongodb

I have this type of data for reference
{
"_id": "62fe02deff92f90b7095ce86",
"status": true,
"isDeleted": false,
"jobId": "60631e25835eacf5321e178a",
"scheduleStartDate": "2021-03-10T12:51:13.000Z",
"scheduleEndDate": "2021-03-1oT13:21:13.000Z",
"round": "L1",
"createdAt": "2021-03-10T12:51:18.535Z",
"updatedAt":"2021-03-10T12:51:18.535Z",
"__v": 0
}
{
"_id": "62fe02deff92f90b7095ce87",
"status": true,
"isDeleted": false,
"jobId": "60643f89983fec5c29cb9950",
"scheduleStartDate": "2021-03-12T12:51:13.000Z",
"scheduleEndDate": "2021-03-12T13:21:13.000Z",
"round": "L1",
"createdAt": "2021-03-10T12:51:18.535Z",
"updatedAt":"2021-03-10T12:51:18.535Z",
"__v": 0
}
{
"_id": "62fe02deff92f90b7095ce87",
"status": true,
"isDeleted": false,
"jobId": "60643f89983fec5c29cb9950",
"scheduleStartDate": "2021-03-13T12:51:13.000Z",
"scheduleEndDate": "2021-03-13T13:21:13.000Z",
"round": "L1",
"createdAt": "2021-03-10T12:51:18.535Z",
"updatedAt":"2021-03-10T12:51:18.535Z",
"__v": 0
}
{
"_id": "62fe02deff92f90b7095ce87",
"status": true,
"isDeleted": false,
"jobId": "60643f89983fec5c29cb9950",
"scheduleStartDate": "2021-03-14T12:51:13.000Z",
"scheduleEndDate": "2021-03-14T13:21:13.000Z",
"round": "L1",
"createdAt": "2021-03-10T12:51:18.535Z",
"updatedAt":"2021-03-10T12:51:18.535Z",
"__v": 0
}
I have first filter data using date range like this.
** First filter query like**
$match: {
jobId: { $in: value.jobIds },
scheduleStartDate: { $gte: startDate, $lte: endDate },
}
So Its getting data list. After this list I need to add more specific date filter not range only specific date which is come from API request like
"dates": [
"11-03-2021",
"12-03-2021",
"13-03-2021",
"14-03-2021"
],
So by using this I make query for filter which is use in aggregation that specific data which I want. that query like
if (value.dates) {
value.dates = value.dates.map((date) => {
return moment(date, "DD/MM/YYYY").format("YYYY-MM-DD[T]HH:mm:ss");
});
filterArray.push({
$match: {
$and: {scheduleStartDate: value.dates},
},
});
}
But I get empty result set because $in not match condition so what should I do for use specific date list.
my aggregation query like
const result = await slotModel.aggregate([
{
$match: {
userId: { $in: value.userIds },
scheduleStartDate: { $gte: startDate, $lte: endDate },
},
},
{
$lookup: {
from: "myjobs",
localField: "jobId",
foreignField: "_id",
as: "job",
},
},
{
$match: {
$and: filterArray,
},
},
{
$project: {
round: 1,
type: 1,
mode: 1,
scheduleStartDate: 1,
scheduleEndDate: 1,
feedbackId: 1,
},
},
]);
return result;
Thanks' in advance.

$lookup ObjectId in an array of ObjectId mongoose

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
}
}
])

MongoDB match in aggregation lookup

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
}
}
])

Is it possible to make a string date comparision inside the mongo $filter cond operator?

In this case, to fetch more compact data from MongoDB, I need to filter subdocument (records) by date value that has a string type. As you can see below, the record document is a nested array.
[
{
"_id": 14,
"isActive": true,
"name": "D.HONGKONG-1",
"factory_id": 10,
"factory_name": "CHAOI",
"branches":
{
"_id": 205,
"isActive": true,
"name": "DZZ NUCE",
"region_id": 14,
"owner_name": "A",
"phone": "",
"records": [
{
"date": "24-10-2020",
"sales": [
{
"time": "17:58",
"explanation": "DAILY CALCULATION",
"type": "DAILY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
}],
"stocks": [
{
"time": "17:58",
"explanation": "DELIVERY COMPL",
"type": "DELIVERY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
},
{
"time": "17:58",
"explanation": "DAILY S. ENTRY",
"type": "DAILY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
}],
"delivery":
{
"P": 0,
"K": 0,
"U": 0
},
"material": []
},
{
"date": "23-10-2020",
"sales": [
{
"time": "17:58",
"explanation": "",
"type": "DAILY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
}],
"stocks": [
{
"time": "17:58",
"explanation": "",
"type": "DELIVERY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
},
{
"time": "17:58",
"explanation": "",
"type": "DAILY",
"quantity":
{
"P": 0,
"K": 0,
"U": 0
}
}],
"delivery":
{
"P": 0,
"K": 0,
"U": 0
},
"material": []
}]
}
}]
When I try to achieve this goal by using the script below, I have encountered some issues listed below.
ConversionFailure (code:241):
I think $dateFromString couldn't consume "$$record.date" filter value. It is working when I use it without $dateFromString.
LocationError (code:31261):
While using the $function to compare dates, the cond argument of $function throws an error like this. So, I couldn't use a function too.
aggregate([{
$match: {
factory_id: parseInt(factoryId),
isActive: true
}
},
{
$lookup: {
from: 'branches',
localField: '_id',
foreignField: 'region_id',
as: 'branches',
},
},
{
$unwind: {
path: '$branches'
}
},
{
$project: {
name: 1,
factory_id: 1,
factory_name: 1,
isActive: 1,
// 'order': 1,
'branches._id': 1,
'branches.name': 1,
'branches.isActive': 1,
'branches.region_id': 1,
'branches.owner_name': 1,
'branches.phone': 1,
'branches.records': {
$filter: {
input: '$branches.records',
as: 'record',
cond: {
$eq: [{
$dateFromString: {
dateString: "11-11-2021",
format: "%d-%m-%Y"
}
},
{
$dateFromString: {
dateString: "$$record.date",
format: "%d-%m-%Y"
}
}
]
}
}
}
}
}
])
I really didn't find a solution to compare these dates inside $filter cond to complete my requirement. What are the possible solutions? Thanks
I have solved my problem myself. It may be a workaround but it works now.
In the $filter operator cond attribute needs the same date object to compare. However, the parsing is impossible for $filter reference values, due to the methods weren't able to read them. So at this point, to do this, we need to use the $convert operator as below.
cond: {
$gte: [{
$dateFromString: {
dateString: lastDate.format('DD-MM-YYYY'),
format: '%d-%m-%Y',
},
},
{
$dateFromString: {
dateString: {
$convert: {
input: '$$record.date',
to: 'string',
},
},
format: '%d-%m-%Y',
},
},
]
}