Flter mongodb database using mongoose nodejs - node.js

I need to filter some users according to some fixed criteria. I have a user collection and a talent collection. The talent collection holds the reference to a master category collection.
What I need is to filter these users according to the category in the talent collection and some keys from the user collection.
For example I need to search for a user whose gender is 'male' and education 'BTech' and will have talents as a programmer and tester
my user collection is like,
{
"_id": "5f1939239bd35429ac9cd78f",
"isOtpVerified": "false",
"role": "user",
"adminApproved": 1,
"status": 0,
"languages": "Malayalam, Tamil, Telugu, Kannada",
"name": "Test user",
"email": "test#email.com",
"phone": "1234567890",
"otp": "480623",
"uid": 100015,
"bio": "Short description from user",
"dob": "1951-09-07T00:00:00.000Z",
"gender": "Male",
"education": "Btech",
"bodyType": "",
"complexion": "",
"height": "",
"weight": "",
"requests": [],
"location": {
"place": "place",
"state": "state",
"country": "country"
},
"image": {
"avatar": "5f1939239bd35429ac9cd78f_avatar.jpeg",
"fullsize": "5f1939239bd35429ac9cd78f_fullsize.png",
"head_shot": "5f1939239bd35429ac9cd78f_head_shot.jpeg",
"left_profile": "5f1939239bd35429ac9cd78f_left_profile.png",
"right_profile": "5f1939239bd35429ac9cd78f_right_profile.png"
},
"__v": 42,
"createdAt": "2020-07-23T07:15:47.387Z",
"updatedAt": "2020-08-18T18:54:22.272Z",
}
Talent collection
[
{
"_id": "5f38efef179aca47a0089667",
"userId": "5f1939239bd35429ac9cd78f",
"level": "5",
"chars": {
"type": "Fresher",
},
"category": "5f19357b50bcf9158c6be572",
"media": [],
"createdAt": "2020-08-16T08:35:59.692Z",
"updatedAt": "2020-08-16T08:35:59.692Z",
"__v": 0
},
{
"_id": "5f3b7e6f7e322948ace30a2c",
"userId": "5f1939239bd35429ac9cd78f",
"level": "3",
"chars": {
"type": "Fresher",
},
"category": "5f19359250bcf9158c6be573",
"media": [
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c22573065f84a48e04a14",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_undefined.jpeg",
"description": "test",
"fileType": "image",
"caption": "test file"
},
{
"adminApproved": 0,
"status": 0,
"_id": "5f3c2d7a8c7f8336b0bfced2",
"file": "id=5f1939239bd35429ac9cd78f&dir=test&img=5f1939239bd35429ac9cd78f_image_1.jpeg",
"description": "this is a demo poster for testing",
"fileType": "image",
"caption": "A Test Poster"
}
],
"createdAt": "2020-08-18T07:08:31.532Z",
"updatedAt": "2020-08-18T19:35:22.899Z",
"__v": 2
}
]
And the category in the above document is a separate one populated to this. the category collection as,
[
{
"_id": "5f19359250bcf9158c6be573",
"status": true,
"title": "Testing",
"description": "Application tester",
"code": "test",
"characteristics": [],
"createdAt": "2020-07-23T07:00:34.221Z",
"updatedAt": "2020-07-23T07:00:34.221Z",
"__v": 0
},
{
"status": true,
"_id": "5f29829a705b4e648c28bc88",
"title": "Designer",
"description": "UI UX Designer",
"code": "uiux",
"createdAt": "2020-08-04T15:45:30.125Z",
"updatedAt": "2020-08-04T15:45:30.125Z",
"__v": 0
},
{
"_id": "5f19357b50bcf9158c6be572",
"status": true,
"title": "programming",
"description": "Java programmer",
"code": "program",
"createdAt": "2020-07-23T07:00:11.137Z",
"updatedAt": "2020-07-23T07:00:11.137Z",
"__v": 0
}
]
So my filter terms will be;
{
categories: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"],
minAge: 18,
maxAge: 25,
minHeight: 5,
maxHeight: 6,
minWeight: 50,
maxWeight: 80,
complexion: "white",
gender: "male",
}
And the expected result will be a user have both the above talents and followed conditions,
{
users: { ..User details.. },
medias: { ...medias from the matching talents.. }
}

If there are two collections you need to join them either by primary key or _id with foriegn fields and you can use $lookup with $match to filter down.
Documentation

You need to use $lookup with pipeline,
$match you condition for category match
$lookup to join users collection
$match conditions for users collections fields
$match exclude documents that don't found matching users of criteria passed in conditions
db.talents.aggregate([
{
$match: {
category: { $in: ["5f19359250bcf9158c6be573", "5f19357b50bcf9158c6be572"] }
}
},
{
$lookup: {
from: "users",
as: "users",
let: { userId: "$userId" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$$userId", "$_id"] },
{ $eq: ["$gender", "Male"] },
{ $eq: ["$education", "Btech"] }
// ... add you other match criteria here
]
}
}
}
]
}
},
{ $match: { users: { $ne: [] } } }
])
Playground

Related

$lookup and $group on Mongodb Aggregation

So i have an document of answers from user with structure like this:
[{
"_id": {
"$oid": "636e685d1e1b4aa82f7e87c7"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180061,
"updatedAt": 1668180061,
"__v": 0,
"position": "Foreman",
"department": "Production"
},
{
"_id": {
"$oid": "636e699c1e1b4aa82f7e87cb"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180380,
"updatedAt": 1668180380,
"__v": 0,
"department": "Production",
"position": "Foreman"
},
{
"_id": {
"$oid": "636e6ace1e1b4aa82f7e87cf"
},
"userId": {
"$oid": "6369b17b11e02557349d8e37"
},
"formId": {
"$oid": "6361d3bf914c7e5a21efa190"
},
"title": "Order Kerja Produksi (KSNI)",
"username": "22000510",
"date": "2022-11-11",
"createdAt": 1668180686,
"updatedAt": 1668180686,
"__v": 0,
"department": "Production",
"position": "Foreman"
}
]
each NIK has assigned with SPV on the Users document, that have structure like this:
{
"_id": {
"$oid": "6369b17b11e02557349d8de6"
},
"password": "$2b$10$whBbgZRMsIMCgKy/EJAwXefSdZNnrK5b.cSOYXTqu7g5a2uwCddKm",
"NIK": "19000298",
"department": "Production",
"__v": 0,
"createdAt": 1667871099,
"updatedAt": 1667871099,
"plant": "RANC",
"Gedung_Zona": "No Status",
"SPV": "JAMJAM J",
"Sector": "2"
},
{
"_id": {
"$oid": "6369b17b11e02557349d8de7"
},
"password": "$2b$10$whBbgZRMsIMCgKy/EJAwXefSdZNnrK5b.cSOYXTqu7g5a2uwCddKm",
"NIK": "20000100",
"Group_Shift": "R1",
"role": "user",
"__v": 0,
"createdAt": 1667871099,
"updatedAt": 1670974129,
"plant": "RANC",
"Gedung_Zona": "No Status",
"SPV": "JAMJAM J",
"Sector": "3"
},
]
I want to aggregate the answers from answers document with condition from users document where condition like this:
{$match:{SPV:"SPV_name"}}
Is that a possible way to produce it into this kind of response with condition above using $lookup and $group?
If thats possible any help on how to produce that?
any help will be very thankful
Here is what i want the response from the query..
{
_id:1243135421412,
formId:123123123123,
title:"title of the question",
username:22004627,
date:2022-10-10,
createdAt:1234125525,
SPV:"SPV_NAME",
},
{
_id:1243135421412,
formId:123123123123,
title:"title of the question",
username:22004777,
date:2022-10-12,
createdAt:1234125525,
SPV:"SPV_NAME",
}
here is my try but it keeps returning error :
MongoServerError: Expression $arrayElemAt takes exactly 2 arguments. 1 were passed in.
Here is my try:
db.answers.aggregate([{$lookup:{from:"users",pipeline:[{$match:{SPV:"JAMJAM JAMALUDIN"}}],as:"data"}}])

Search Filter MongoDB Nestjs

When Implementing a search filter on a document withh populated documents and array of object, How can I enable the search filter to checkout the populated document or array for the searched word?
What I have only checks through the surface fields
async findAllFeedbacks(user: any, payload: FilterDto) {
if (payload.fields) {
const query = await this.distributionChannelsDocumentModel
.find({
[payload.fields]: {
$regex: `${payload.searchFilter}`,
$options: 'i'
},
})
.clone()
.where({ business: user.business })
.populate({
path: 'feedbackId',
// match: { 'feedbackId[payload.fields]': { $regex: `${payload.searchFilter}` } }
})
return { query, total: query.length }
} else {
const query = await this.distributionChannelsDocumentModel
.find()
.clone()
.where({ business: user.business })
.populate('feedbackId')
return { query, total: query.length }
}
}
Here is a response sample:
{
"query": [
{
"_id": "62a8645641b312b3a04a7233",
"feedbackId": {
"_id": "62a8642b41b312b3a04a722a",
"title": "Monthly Feedback test",
"questions": [
{
"title": "Rate Our Services test",
"subtitle": "Customer retention is our priority",
"type": "SMILEY"
}
],
"thankYouMessage": "Thanks for dropping a feedback",
"allowComment": true,
"allowEmail": true,
"allowFullName": false,
"allowAttachment": false,
"status": "Active",
"business": "62a83f5ab4b33de7307e9cb8",
"user": "62a83f59b4b33de7307e9cb6",
"createdAt": "2022-06-14T10:34:19.709Z",
"updatedAt": "2022-06-14T10:34:19.709Z",
"__v": 0
},
"user": "62a83f59b4b33de7307e9cb6",
"distributionChannelType": [
"email"
],
"meta": [
{
"sender": "string",
"subject": "string",
"positioning": "string",
"timing": "string",
"brandColor": "string"
}
],
"createdAt": "2022-06-14T10:35:02.092Z",
"updatedAt": "2022-06-14T10:35:02.092Z",
"__v": 0
},
{
"_id": "62b1c87510fae7f3a54b13b2",
"feedbackId": {
"_id": "62ac55d0b28630c3a8c9b940",
"title": "Yearly Feedback",
"questions": [
{
"title": "Rate Our Services",
"subtitle": "We love to hear from you! How is your Jumia food experience",
"type": "SMILEY"
}
],
"thankYouMessage": "Thanks for dropping a feedback",
"allowComment": true,
"allowEmail": true,
"allowFullName": false,
"allowAttachment": false,
"status": "Active",
"business": "62ac434542452ccb513f2241",
"user": "62ac434542452ccb513f223f",
"createdAt": "2022-06-17T10:22:08.863Z",
"updatedAt": "2022-06-17T10:22:08.863Z",
"__v": 0
},
"user": "62ac434542452ccb513f223f",
"distributionChannelType": [
"sms"
],
"meta": [
{
"position": "bottom",
"timing": "",
"brandColor": "#444"
}
],
"createdAt": "2022-06-21T13:32:37.895Z",
"updatedAt": "2022-06-21T13:32:37.895Z",
"__v": 0
}
],
"total": 2
}
In the above response, feedbackId is the populated document and questions is the array I would also want to search through when using the search filter

How to filter results from collection the $lookup in mongoose

i want to filter the result as the following in mongodb. I use $lookup to populate the result from another collection. Please check my following code
This code below is what i get
{
"_id": "5f3d563122de0730d0f6a754",
"barcode": "1234",
"productname": "Lays Packet",
"brandName": "Lays",
"productSize": "12",
"price": "12",
"quant": "12",
"imageurl": "http://localhost:3000/images/imageurl-1597855281050.jpg",
"remaining": "12",
"creator": "3d943b957fb5db510d824c5cbd6e8f7d",
"__v": 0,
"source": [
{
"_id": "5f3a9bbc325a074240a1a815",
"firstname": "test",
"lastname": "test",
"storename": "test",
"gst": "test",
"phoneNumber": 1,
"email": "1#demo.com",
"address1": "test",
"address2": "test",
"city": "test",
"state": "test",
"country": "test",
"zip": "1",
"password": "1",
"usertype": 3,
"unique_SHOP": "3d943b957fb5db510d824c5cbd6e8f7d",
"__v": 0
}
]
},
How to retrieve only unique_SHOP and zip from source listing.I want result like the one below with one or more fields
{
"_id": "5f3d563122de0730d0f6a754",
"barcode": "1234",
"productname": "Lays Packet",
"brandName": "Lays",
"productSize": "12",
"price": "12",
"quant": "12",
"imageurl": "http://localhost:3000/images/imageurl-1597855281050.jpg",
"remaining": "12",
"creator": "3d943b957fb5db510d824c5cbd6e8f7d",
"__v": 0,
"source": [
{
"zip": "1",
"unique_SHOP": "3d943b957fb5db510d824c5cbd6e8f7d",
}
]
},
The query i use
List.aggregate([
{$match:
{ productname: { $regex: req.params.query,$options: "i" }}
},
{ $lookup:{
from: "suppliers",
localField: "creator",
foreignField: "unique_SHOP",
as: "source"
}
},
])
You can try $lookup with pipeline,
$match condition of creator id
$project to display required fields
{
$lookup: {
from: "suppliers",
as: "source",
let: { creator: "$creator" },
pipeline: [
{
$match: {
$expr: { $eq: ["$$creator", "$_id"] }
}
},
{
$project: {
_id: 0,
zip: 1,
unique_SHOP: 1
}
}
]
}
}
Playground

How to filter if using aggregate and $lookup in mongoose?

I have a list of question for a patient, each patient have an Id in mongoDB (patientId). In every question I have many comments (I separate each comment by type of comment: type = "ask" for patient follow-up note comment, type = "answer" for doctor comment)
I want to return an array of comment but filter by type = "ask", how can I do. At the present, I only return by array of all comments include patient and doctor. I am using aggregate and lookup like this.
How can I filter by type? Please help me? Thanks
findQuestionByPatientId(req, res, next){
Questions.aggregate([
{
$match: {
$and:[{"patientId":ObjectId(req.params.patientId)}]
}
},
{
$lookup:
{
from: "comments", // at present It's list all comments include type ="ask" and type = "answer". I want to filter only comment with type ="ask"
localField: "_id",
foreignField: "questionId",
as: "comments"
}
}
]).then(data => {
res.send({"data": data, "resultCode": 1, "message " : ""});
});
}
Below is example data, the list have 2 question:
{
"data": [
{
"_id": "5d8385844ad1d5001058f220",
"patientId": "5c80930d447df7735138693e",
"title": "I have a stomachache",
"askFor": "myself",
"age": 28,
"gender": "",
"askContent": "I have a stomachache, please give me a prescription",
"attachment": "5d8385844ad1d5001058f21f",
"askToDoctor": "5d1cd947231ceb95b8838c1b",
"createdBy": "5c80930d447df7735138693e",
"askStatus": "Awaiting Reply",
"approvedBy": "",
"approved": false,
"createdAt": "2019-09-19T13:41:24.874Z",
"updatedAt": "2019-09-19T13:41:24.874Z",
"__v": 0,
"comments": [
{
"_id": "5da0039d9a3d852cf08aa89d",
"content": "I sent my image in attached file",
"type": "ask",
"questionId": "5d8385844ad1d5001058f220",
"approved": false,
"createdBy": "5d1cd947231ceb95b8838c1b",
"attachedFile": null,
"approvedBy": "5d1cd947231ceb95b8838c1b",
"createdAt": "2019-10-11T04:22:53.538Z",
"updatedAt": "2019-10-11T04:22:53.538Z",
"__v": 0
},
{
"_id": "5da003a39a3d852cf08aa89f",
"content": "Doctor, plz give me a detail guide",
"type": "ask",
"questionId": "5d8385844ad1d5001058f220",
"approved": false,
"createdBy": "5d1cd947231ceb95b8838c1b",
"attachedFile": null,
"approvedBy": "5d1cd947231ceb95b8838c1b",
"createdAt": "2019-10-11T04:22:59.105Z",
"updatedAt": "2019-10-11T04:22:59.105Z",
"__v": 0
},
{
"_id": "5da003aa9a3d852cf08aa8a1",
"content": "I sent you the guide to take medicine in attached",
"type": "reply",
"questionId": "5d8385844ad1d5001058f220",
"approved": false,
"createdBy": "5d1cd947231ceb95b8838c1b",
"attachedFile": null,
"approvedBy": "5d1cd947231ceb95b8838c1b",
"createdAt": "2019-10-11T04:23:06.896Z",
"updatedAt": "2019-10-11T04:23:06.896Z",
"__v": 0
}
]
},
{
"_id": "5d8b2e9406e021904a797838",
"patientId": "5c80930d447df7735138693e",
"title": "I got a flu",
"askFor": "Myseft",
"age": 34,
"gender": "",
"askContent": "I got a flu, please give me a medicine",
"attachment": "5d8b2e9406e021904a797837",
"askToDoctor": "5d1cd947231ceb95b8838c1b",
"createdBy": "5c80930d447df7735138693e",
"askStatus": "Awaiting Reply",
"approvedBy": "",
"approved": false,
"createdAt": "2019-09-25T09:08:36.891Z",
"updatedAt": "2019-09-25T09:08:36.891Z",
"__v": 0,
"comments": []
}
],
"resultCode": 1,
"message ": ""
}
The below aggregation will return your whole documents, with comments filtered by type :
db.collection.aggregate([
{
$addFields: {
comments: {
$filter: {
input: "$comments",
as: "comment",
cond: {
$eq: [
"$$comment.type",
"ask"
]
}
}
}
}
}
])

Unwind inside lookup in Mongoose

I have 2 entities to merge: Customer and Feedback. Feedback contains an embedded array of upvotes (Upvote)
A customer is not able to upvote more than once for a specific feedback.
What I would like to achieve is - given a specific feedback id - get the complete list of customers with an additional virtual attribute that states whether he/she upvoted the given feedback.
Customer.aggregate(
[
{
$match: { company_id: new ObjectID(req.user.company_id) }
},
{
$lookup: {
from: 'feedbacks',
let: { 'c_id': '$_id' },
pipeline: [
{
$unwind: '$upvotes'
},
{
$match: { $expr: { $eq: ['$upvotes.customer_id._id', '$$c_id'] } }
}
],
as: 'upvotes'
}
}
],
function(err, customers) {
if (err) {
console.log(err);
res.status(400).send(err);
} else {
res.send({ customers });
}
}
);
To do that I have to look through the list of upvotes for that specific feedback and, then, join it with the customer table using the customer_id.
The above mentioned approach does not work. Any suggestion what I am doing wrong?
Sample data (Feedback)
{
"size": 0,
"points": 50,
"status": "open",
"potential": 0,
"real": 5000,
"_id": "5c3d033271ceb7edc37d156c",
"title": "Custom Invoice Templates",
"description": "Provide an editor to create custom invoices.",
"owner_id": {
"_id": "5c3b684f7cec8be977c2a465",
"email": "maurizio#acme.com"
},
"company_id": "5c3b684f7cec8be977c2a462",
"project_id": "5c3b68507cec8be977c2a468",
"upvotes": [
{
"_id": "5c3fa5b371ceb7edc37d159a",
"comments": "bbbb",
"priority": "should",
"customer_id": {
"size": 0,
"potential": 0,
"real": 5000,
"_id": "5c3b68507cec8be977c2a485",
"name": "Oyomia Ltd."
},
"owner_id": {
"_id": "5c3b684f7cec8be977c2a465",
"email": "maurizio#acme.com"
}
}
],
"updatedAt": "2019-01-16T21:44:19.215Z",
"createdAt": "2019-01-14T21:46:26.286Z",
"__v": 0
}
Sample data (Customer)
{
"size": 0,
"potential": 0,
"real": 5000,
"_id": "5c3b68507cec8be977c2a485",
"name": "Oyomia Ltd.",
"contact": {
"_id": "5c40f8de71ceb7edc37d15ab",
"name": "Nick Page",
"email": "np#oyoma.com"
},
"company_id": "5c3b684f7cec8be977c2a462",
"deals": [
{
"value": 5000,
"_id": "5c3b68507cec8be977c2a487",
"name": "Armour batch",
"status": "won",
"type": "non_recurring",
"updatedAt": "2019-01-13T16:33:20.870Z"
}
],
"__v": 0,
"updatedAt": "2019-01-17T21:51:26.877Z"
}

Resources