How to use project in nested array using $In to get Data - mongodb

I want to get to use array for searching data in mongo
Here is my data
{
"_id": ObjectID("5f0d6e394556410d486f6828"),
"branchId": "exampleId",
"info": [
{
"date": "12-10-09",
"programs": [
{
"programId": "ObjectId1",
},
{
"programId": "ObjectId2",
},
{
"programId": "ObjectId3",
},
],
}
],
}
I want to find programId by using array here is my array
const programIdArr = ["ObjectId1","ObjectId2"]
I want out put
NOTE : I want to use programIdArr search in mySql we can use something like whereIn
{
"_id": ObjectID("5f0d6e394556410d486f6828"),
"branchId": "exampleId",
"info": [
{
"date": "12-10-09",
"programs": [
{
"programId": "ObjectId1",
},
{
"programId": "ObjectId2",
},
],
}
],
}
Here is what I try to do
const program =
Models.aggregate([
{ $match: { _id: Mongoose.Types.ObjectId('5f0d6e394556410d486f6828') } },
{
//for first project I already get where date = 12-10-09
$project: {
info: {
$filter: {
input: '$info',
as: 'info',
cond: { $eq: ['$$info.date', '12-10-09'] },
},
},
},
// in this project I try to filter programId by using programIdArr It doesn't work
$project: {
info: {
$filter: {
input: '$info.programs.programId',
as: 'programId',
cond: { $in: [programIdArr] },
},
},
},
},
{ $unwind: { path: '$info' } },
])
.exec()
As I read document $in it's return only true of false I try also try to use $all but It didn't work too.

You can try this
[{
$match: {
_id: ObjectId("5f0d6e394556410d486f6828")
}
}, {
$unwind: {
path: "$info",
preserveNullAndEmptyArrays: false
}
}, {
$project: {
branchId: 1,
"info.date": 1,
"info.programs": {
$filter: {
input: '$info.programs',
as: 'p',
cond: {
$in: ["$$p.programId", ["ObjectId1", "ObjectId2"]]
},
},
}
}
}, {
$group: {
_id: "$_id",
branchId: {
$first: "$branchId"
},
info: {
$addToSet: "$info"
}
}
}]
Working Mongo playground

Related

Extract value from an array of objects in mongodb aggregate

I am new to mongodb,
I'm trying to extract expectedDeliveryTime from the following data:
{
"from": "Giza",
"delivery_rule": [
{
"to": "Giza",
"expectedDeliveryTime": 3
},
{
"to": "Riyadh",
"expectedDeliveryTime": 2
}
]
}
I am trying to fetch expectedDeliveryTime WHERE from='Giza' and to='Riyadh'
MySQL equivalent would be SELECT expectedDeliveryTime FROM delivery_rules AS d WHERE d.from='Giza' AND d.to='Giza'
Below is part of my code
{
$lookup: {
from: 'Setting',
pipeline: [
{
$match: {
$expr: { $eq: ['$name', 'delivery_rules'] },
},
}
],
as: 'delivery_rules',
}
},
{
$addFields: {
delivery_rules: "$delivery_rules.value"
}
},
{ $unwind: '$delivery_rules' },
{
$addFields: {
delivery_rules: {
$filter: {
input: "$delivery_rules",
as: "rule",
cond: {
$eq: [
"$$rule.from",
"Giza"
]
},
}
}
}
},
{
$group: {
expectedDeliveryTime: { $first: '$delivery_rules' },
}
},
{
$project: {
_id: 0,
expectedDeliveryTime: 1,
}
}
You can solve this using simply $match and $unwind
db.collection.aggregate([
{
"$match": {
"from": "Giza"
}
},
{
"$unwind": "$delivery_rule"
},
{
"$match": {
"delivery_rule.to": "Riyadh"
}
},
{
$project: {
_id: 0,
expectedDeliveryTime: "$delivery_rule.expectedDeliveryTime"
}
}
])
Here is the Mongo playground for your reference.

Mongo query for lookup array of keys which is itself an item in a nested array

My first collection is as below, I am searching the document with the email and match the particular jobid inside the jobs array. Then insert the document of second collection by matching _id with jobs.Process.profile_id.
{
"_id": {
"$oid": "6229d3cfdbfc81a8777e4821"
},
"jobs": [
{
"job_ID": {
"$oid": "62289ded8079821eb24760e0"
},
"Process": [
{
"profile_id": {
"$oid": "6285e571681188e83d434797"
}
},
{
"profile_id": {
"$oid": "6285e571681188e83d434799"
}
}
],
},
{
"job_ID": {
"$oid": "6228a252fb4554dd5c48202a"
},
"Process": [
{
"profile_id": {
"$oid": "62861067dc9771331e61df5b"
}
}
],
},
{
"job_ID": {
"$oid": "622af1c391b290d34701af9f"
},
"Process": [
""
],
}
],
"email": "********#gmail.com"
}
and my second collection is, I need to insert this document in my first collection by matching with jobs.Process.profile_id.
{
"_id": {
"$oid": "6285e571681188e83d434797"
},
"Name": "Lakshdwanan",
"Location":"California"
}
I have tried with query,
aggregate([
{ $match: { email: email } },
{
$lookup: {
from: 'user__profiles',
localField: 'jobs.Process.profile_id',
foreignField: '_id',
as: 'jobings',
},
},
{
$addFields: {
jobings: {
$map: {
input: {
$filter: {
input: '$jobs',
as: 'm',
cond: {
$eq: ['$$m.job_ID', objInstance],
},
},
},
as: 'm',
in: {
$mergeObjects: [
{
$arrayElemAt: [
{
$filter: {
input: '$jobings',
cond: {
$eq: ['$$this._id', '$$m.Process.profile_id'],
},
},
},
0,
],
},
'$$m',
],
},
},
},
},
},
{
$project: {
jobings: 1,
_id: 0,
},
},
]);
My output should only display second collection document based on the first collection document matching.
EDIT: If you want the data for a specific job only, it is better to $filter the jobs before the $lookup step. After the $lookup, just $unwind and format:
db.firstCol.aggregate([
{
$match: {email: email}
},
{
$project: {
jobs: {
$filter: {
input: "$jobs",
as: "item",
cond: {$eq: ["$$item.job_ID", objInstance]}
}
},
_id: 0
}
},
{
$lookup: {
from: "user__profiles",
localField: "jobs.Process.profile_id",
foreignField: "_id",
as: "jobings"
}
},
{
$project: {res: "$jobings", _id: 0}
},
{
$unwind: "$res"
},
{
$replaceRoot: {newRoot: "$res"}
}
])
Playground
The jobs.Process.profile_id is the user__profiles _id, so no need to merge anything...The results are documents from user__profiles collection "as is" but they can be formatted as wanted..._id key name can be renamed profile_id easily.

MongoDB match computed value

I've created an aggregate query but for some reason it doesn't seem to work for custom fields created in the aggregation pipeline.
return this.repository.mongo().aggregate([
{
$match: { q1_avg: { $regex: baseQuery['value'], $options: 'i' } }, // NOT WORKING
},
{
$group: {
_id: '$product_sku',
id: { $first: "$_id" },
product_name: { $first: '$product_name' },
product_category: { $first: '$product_category' },
product_sku: { $first: '$product_sku' },
q1_cnt: { $sum: 1 },
q1_votes: { $push: "$final_rating" }
},
},
{
$facet: {
pagination: [ { $count: 'total' } ],
data: [
{
$project: {
_id: 1,
id: 1,
product_name: 1,
product_category: 1,
product_sku: 1,
q1_cnt: 1,
q1_votes: {
$filter: {
input: '$q1_votes',
as: 'item',
cond: { $ne: ['$$item', null] }
}
},
},
},
{
$set: {
q1_avg: { $round: [ { $avg: '$q1_votes' }, 2 ] },
}
},
{ $unset: ['q1_votes'] },
{ $skip: skip },
{ $limit: limit },
{ $sort: sortList }
]
}
},
{ $unwind : "$pagination" },
]).next();
q1_avg value is an integer and as far as I know, regex only works with strings. Could that be the reason

MongoDB Aggregation - Select only same value from array inside lookup

I have aggregation like this:
Produk.aggregate([
{
$lookup: {
from: "kis_m_kategoriproduks",
localField: "idSubKategori",
foreignField: "subKategori._id",
as: "kategori",
},
},
{ $unwind: "$kategori" },
{ $sort: { produk: 1 } },
{
$project: {
_id: 0,
id: "$id",
dataKategori: {
idKategori: "$kategori._id",
kategori: "$kategori.kategori",
idSubKategori: "$idSubKategori",
subKategori: "$kategori.subKategori",
},
},
},
])
current result is :
{
"status": "success",
"data": [
{
"dataKategori": {
"idKategori": "6195bbec8ee419e6a9b8329d",
"kategori": "Kuliner",
"idSubKategori": "6195bc0f8ee419e6a9b832a2",
"subKategori": [
{
"nama": "Food",
"_id": "6195bc0f8ee419e6a9b832a2"
},
{
"nama": "Drink",
"_id": "6195bc258ee419e6a9b832a8"
}
]
}
}
]
}
I only want to display data in subKategori that the _id match with idSubKategori. this what I expected:
{
"status": "success",
"data": [
{
"dataKategori": {
"idKategori": "6195bbec8ee419e6a9b8329d",
"kategori": "Kuliner",
"idSubKategori": "6195bc0f8ee419e6a9b832a2",
"subKategori": [
{
"nama": "Food",
"_id": "6195bc0f8ee419e6a9b832a2"
}
]
}
}
]
}
here is my $kategori schema:
const schema = mongoose.Schema(
{
kategori: {
type: String,
required: true,
unique: true,
},
subKategori: [
{
id: mongoose.Types.ObjectId,
nama: String,
},
],
},
{
timestamps: false,
}
);
any suggestion?
I fix the problem by add $filter inside $project like this:
dataKategori: {
idKategori: "$kategori._id",
kategori: "$kategori.kategori",
subKategori: {
$arrayElemAt: [
{
$filter: {
input: "$kategori.subKategori",
as: "sub",
cond: { $eq: ["$$sub._id", "$idSubKategori"] },
},
},
0,
],
},
},
reference: https://stackoverflow.com/a/42490320/6412375

Mongo Sort Aggregation not working on Sub Document

Trying to sort the sub-key on the document.
Example of data from the pipeline. Incorrect sort order for subkey availability.startIso
{
"_id": "60e458d7b896de9c8e44d6c9",
"uid": "6233ed1d8b154aa79d1435b5",
"name": "Pale",
"phoneNumber": "+19999813917",
"profileMedia": {
"url": "https://storage.googleapis.com/refresh-me-dev.appspot.com/dummy_photos/dummy_1.jpg",
"type": "photo"
},
"createdIso": "2021-07-06T13:21:27.513Z",
"isDeleted": false,
"isFlagged": false,
"isBanned": false,
"isAdmin": false,
"isVendor": true,
"lastOpenedAppIso": "2021-07-06T13:21:27.513Z",
"vendorMeta": {
"servicesOffered": [
"swedish"
],
"location": [
0,
0
]
},
"distanceFromPoint": 0,
"availability": [
{
"_id": "60e458d7b896de9c8e44d6cc",
"uid": "dec97d4b1dea44f7b2fa45a5",
"vendorUid": "6233ed1d8b154aa79d1435b5",
"startIso": "2021-07-12T04:07:21.349Z",
"endIso": "2021-07-12T05:07:21.360Z"
},
{
"_id": "60e458d7b896de9c8e44d6ce",
"uid": "a5928ea5c18c4321bd6a9a9b",
"vendorUid": "6233ed1d8b154aa79d1435b5",
"startIso": "2021-07-11T01:52:18.323Z",
"endIso": "2021-07-11T02:52:18.335Z"
}
]
}
Example of the aggregation
let vendors = await mongoDb
.collection<User>(collectionNames.users)
.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [lat, lng] },
spherical: true,
maxDistance: 7500,
distanceField: "distanceFromPoint",
},
},
{
$match: { isVendor: true },
},
{
$match: { "vendorMeta.servicesOffered": { $in: services } },
},
{
$lookup: {
from: "vendor.availability",
localField: "uid",
foreignField: "vendorUid",
as: "availability",
},
},
{
$addFields: {
availability: {
$filter: {
input: "$availability",
as: "availability",
cond: { $and: [{ $gte: ["$$availability.startIso", nowIso] }, { $lte: ["$$availability.endIso", nDaysIso] }] },
},
},
},
},
{ $sort: { "availability.startIso": 1 } },
{ $match: { availability: { $ne: [] } } },
])
.toArray();
This is working as intended, $sort does not work on arrays and can't be used like this. What you can do is $unwind, then $sort and end by $grouping to restore the structure, like so:
[
// ...,
{
$unwind: "$availability"
},
{ $sort: { "availability.startIso": 1 } },
{
$group: {
_id: '$_id',
root: {$first: "$$ROOT"},
availability: {$push: '$availability'}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
'$root',
{ availability: '$availability'}
]
}
}
}
]
Note that i removed the :
{ $match: { availability: { $ne: [] } } },
As it's no longer required because $unwind will remove those documents for you.