MongoDB match expression query not working - javascript

MongoDb query match expression not working.
I have a posts collection and want to return only those posts which match the user Id of the user who created it but my query does not seem to be working.
Sample Dataset
[
// 1
{
"_id": ObjectId("6257047cffd61ab62864c1ae"),
"type": "A",
"source": "B",
"status": "A",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
// 2
{
"_id": ObjectId("6257047cffd61ab62864c1ad"),
"type": "B",
"source": "A",
"status": "A",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
// 3
{
"_id": ObjectId("6257047cffd61ab62864c1ce"),
"type": "A",
"source": "C",
"status": "B",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
// 4
{"_id": ObjectId("6257047cffd61ab62864c1cb"),
"type": "A",
"source": "B",
"status": "C",
"user": ObjectId("622b56250b0af6b049c387d6")
}
]
MongoDb Query:-
db.collection.aggregate([
{
$addFields: {
paramType: "All",
paramSource: "All",
paramStatus: "All",
},
},
{
$match: {
$expr: {
$and: [
{
user: ObjectId("622b55ff0b0af6b049c387d3")
},
{
$or: [
{
$eq: [
"$paramType",
"All"
],
},
{
$eq: [
"$paramType",
"$type"
],
},
],
},
{
$or: [
{
$eq: [
"$paramSource",
"All"
],
},
{
$eq: [
"$paramSource",
"$source"
],
},
],
},
{
$or: [
{
$eq: [
"$paramStatus",
"All"
],
},
{
$eq: [
"$paramStatus",
"$status"
],
},
],
},
],
},
},
},
{
$setWindowFields: {
output: {
totalCount: {
$count: {}
}
}
}
},
{
$sort: {
createdAt: -1
}
},
{
$skip: 0
},
{
$limit: 6
},
{
"$project": {
"paramSource": false,
"paramStatus": false,
"paramType": false,
}
}
])
Query Output:-
[
{
"_id": ObjectId("6257047cffd61ab62864c1ae"),
"source": "B",
"status": "A",
"totalCount": 4,
"type": "A",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
{
"_id": ObjectId("6257047cffd61ab62864c1ad"),
"source": "A",
"status": "A",
"totalCount": 4,
"type": "B",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
{
"_id": ObjectId("6257047cffd61ab62864c1ce"),
"source": "C",
"status": "B",
"totalCount": 4,
"type": "A",
"user": ObjectId("622b55ff0b0af6b049c387d3")
},
{
"_id": ObjectId("6257047cffd61ab62864c1cb"),
"source": "B",
"status": "C",
"totalCount": 4,
"type": "A",
"user": ObjectId("622b56250b0af6b049c387d6")
}
]
The query does not work output contains posts created by all users it is not filtering.

The $match part should look like this:
{
$match: {
$and: [
{
user: ObjectId("622b55ff0b0af6b049c387d3")
},
{
$or: [{paramType: {$eq: "All"}},
{$expr: {$eq: ["$paramType", "$type"]}}
]
},
{
$or: [{paramSource: {$eq: "All"}},
{$expr: {$eq: ["$paramSource", "$type"]}}
]
},
{
$or: [{paramStatus: {$eq: "All"}},
{$expr: {$eq: ["$paramStatus", "$type"]}}
]
}
]
}
}
The $expr should only be assigned to cases where both values are in the document. This query returns 3 / 4 documents, the ones in which user: ObjectId("622b55ff0b0af6b049c387d3")
BTW, the last 3 conditions on this $match stage are redundant, as they will always be true, since the query sets them with the value 'All' on the former stage

Related

javascript extract and convert into new array

I have the following array
[ {
"contactId": "a87d096gd5fuop",
"firstName": "John Doe",
"registrationTypes": {
"selectedOptions": [
{
}
],
"subTotal": 1620.003
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"events": {
"selectedOptions": [
{
"id": "1",
"name": "T1",
"value": "4550006:3",
},
{
"id": "2",
"name": "T2",
"value": "4550005:3",
},
{
"id": "3",
"name": "T3",
"value": "4550003:3",
}
],
"subTotal": 135.003
},
"freeNetworkingFunctions": {
},
"total": 1755.0059999999999
},
{
"contactId": "a097f",
"firstName": "David",
"registrationTypes": {
"selectedOptions": [
{}
],
"subTotal": 899.998
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"member": {
"selectedOptions": [
{
}
],
"subTotal": 228.8
},
"events": {
"selectedOptions": [
{
"id": "4",
"name": "T4",
"value": "4550002:2",
},
{
"id": "5",
"name": "T5",
"value": "4550001:2",
},
{
"id": "6",
"name": "T6",
"value": "4550003:2",
}
],
"subTotal": 135.003
},
"total": 1263.801
}
]
From the above array, I want to extract events, loop all the data and get only values. So my new array should be something like this:
[ {
"contactId": "a87d096gd5fuop",
"firstName": "John Doe",
"registrationTypes": {
"selectedOptions": [
{
}
],
"subTotal": 1620.003
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"events": [
"4550006:3"
"4550005:3",
"4550003:3",
],
},
"freeNetworkingFunctions": {
},
"total": 1755.0059999999999
},
{
"contactId": "a097f",
"firstName": "David",
"registrationTypes": {
"selectedOptions": [
{}
],
"subTotal": 899.998
},
"foo1": {
"selectedOptions": [
],
"subTotal": 0
},
"member": {
"selectedOptions": [
{
}
],
"subTotal": 228.8
},
"events": [
"4550004:2"
"4550008:3",
"4550003:3",
],
"subTotal": 135.003
},
"total": 1263.801
}
]
So it should return the original array, however, events value data should be in one array.
var arr = [];
var r(var i=0;i<data.length;i++){
data.push(arr[i].value);
}
var newData = [...data, arr]
However, this doesn't work. Any help would be highly appreciated.
Use map twice - once on the dataset to iterate over the objects, and within that map to get an array of values from the selectedOptions.
const data=[{contactId:"a87d096gd5fuop",firstName:"John Doe",registrationTypes:{selectedOptions:[{}],subTotal:1620.003},foo1:{selectedOptions:[],subTotal:0},events:{selectedOptions:[{id:"1",name:"T1",value:"4550006:3"},{id:"2",name:"T2",value:"4550005:3"},{id:"3",name:"T3",value:"4550003:3"}],subTotal:135.003},freeNetworkingFunctions:{},total:1755.0059999999999},{contactId:"a097f",firstName:"David",registrationTypes:{selectedOptions:[{}],subTotal:899.998},foo1:{selectedOptions:[],subTotal:0},member:{selectedOptions:[{}],subTotal:228.8},events:{selectedOptions:[{id:"4",name:"T4",value:"4550002:2"},{id:"5",name:"T5",value:"4550001:2"},{id:"6",name:"T6",value:"4550003:2"}],subTotal:135.003},total:1263.801}];
const out = data.map(obj => {
// Destructure the selected options from the
// rest of each object
const { events: { selectedOptions }, ...rest } = obj;
// `map` over the options to just get an array of values
const events = selectedOptions.map(option => {
return option.value;
});
// Return a new object with the new events property
// combined with the other properties again
return { ...rest, events };
});
console.log(out);
Additional documentation
Destructuring assignment
Rest parameters
Spread syntax

MongoDB : - Merge Two Array with same key

I have 3 collections, users, attendances, shifts.
I am trying to get attendances and shifts with the help of users
I have a date in shifts and the Date key in attendances and I am trying to merge both data into 1 as per date, and if not present then that key should be none
Below is the query I tried it is working to some extent but not got the final result
User.aggregate([
{ $sort: { workerId: 1 } },
{
$lookup: {
from: "shifts",
localField: "_id",
foreignField: "employeeId",
pipeline: [
{
$match: {
date: {
$gte: new Date(fromDate),
$lte: new Date(toDate),
},
},
},
{
$project: {
date: 1,
shiftCode: 1,
},
},
{
$sort: {
date: 1,
},
},
],
as: "shifts",
},
},
{
$project: {
_id: 1,
workerId: 1,
shiftListData: "$shifts",
},
},
{
$lookup: {
from: "attendances",
localField: "_id",
foreignField: "employeeId",
pipeline: [
{
$match: {
Date: { $gte: new Date(fromDate), $lte: new Date(toDate) },
},
},
{
$project: {
inTime: 1,
name: 1,
Date: 1,
},
},
],
as: "attendances",
},
},
]);
OutPut
[
{
"workerId": "1005",
"shiftListData": [
{
"_id": "63875e8182ebbe13ee9531d4",
"shiftCode": "HOBGS_1100",
"date": "2022-12-31T00:00:00.000Z"
},
{
"_id": "63b277a2f6a8eccb2d95d407",
"shiftCode": "WO",
"date": "2023-01-01T00:00:00.000Z"
},
{
"_id": "63b27787f6a8eccb2d95cf30",
"shiftCode": "HOBGS_1100",
"date": "2023-01-02T00:00:00.000Z"
},
{
"_id": "63b277a2f6a8eccb2d95d409",
"shiftCode": "HOBGS_1100",
"date": "2023-01-03T00:00:00.000Z"
}
],
"attendances": [
{
"_id": "61307cd385b5055a15cec159",
"Date": "2022-12-31T00:00:00.000Z",
"inTime": "2022-12-31T11:16:10.000Z",
"name": "name2"
},
{
"_id": "63b236ef3980cffaf7715d62",
"inTime": "2023-01-02T07:14:08.000Z",
"Date": "2023-01-02T00:00:00.000Z",
"name": "name2"
}
]
},
{
"workerId": "1006",
"shiftListData": [
{
"_id": "63875e8182ebbe13ee9531d2",
"shiftCode": "HOBGS_1100",
"date": "2022-12-31T00:00:00.000Z"
},
{
"_id": "63b277a2f6a8eccb2d95d403",
"shiftCode": "WO",
"date": "2023-01-01T00:00:00.000Z"
},
{
"_id": "63b27787f6a8eccb2d95cf39",
"shiftCode": "HOBGS_1100",
"date": "2023-01-02T00:00:00.000Z"
},
{
"_id": "63b277a2f6a8eccb2d95d400",
"shiftCode": "HOBGS_1100",
"date": "2023-01-03T00:00:00.000Z"
}
],
"attendances": [
{
"_id": "61307cd385b5055a15cec158",
"Date": "2022-12-31T00:00:00.000Z",
"inTime": "2022-12-31T11:16:10.000Z",
"name": "name"
},
{
"_id": "63b236ef3980cffaf7715d69",
"inTime": "2023-01-02T07:14:08.000Z",
"Date": "2023-01-02T00:00:00.000Z",
"name": "name"
}
]
}
]
I want to merge shiftListData and attendances as per date into one array
Example : -
[
{
"workerId": "1005",
"newData": [
{
"_id": "63875e8182ebbe13ee9531d4",
"shiftCode": "HOBGS_1100",
"date": "2022-12-31T00:00:00.000Z",
"attendanceId": "61307cd385b5055a15cec159",
"attendanceDate": "2022-12-31T00:00:00.000Z",
"inTime": "2022-12-31T11:16:10.000Z",
"name": "name2"
},
{
"_id": "63b277a2f6a8eccb2d95d407",
"shiftCode": "WO",
"date": "2023-01-01T00:00:00.000Z"
},
{
"_id": "63b27787f6a8eccb2d95cf30",
"shiftCode": "HOBGS_1100",
"date": "2023-01-02T00:00:00.000Z",
"attendanceId": "63b236ef3980cffaf7715d62",
"inTime": "2023-01-02T07:14:08.000Z",
"attendanceDate": "2023-01-02T00:00:00.000Z",
"name": "name2"
},
{
"_id": "63b277a2f6a8eccb2d95d409",
"shiftCode": "HOBGS_1100",
"date": "2023-01-03T00:00:00.000Z"
}
]
},
{
"workerId": "1006",
"newData": [
{
"_id": "63875e8182ebbe13ee9531d2",
"shiftCode": "HOBGS_1100",
"date": "2022-12-31T00:00:00.000Z",
"attendanceId": "61307cd385b5055a15cec158",
"attendanceDate": "2022-12-31T00:00:00.000Z",
"inTime": "2022-12-31T11:16:10.000Z",
"name": "name"
},
{
"_id": "63b277a2f6a8eccb2d95d403",
"shiftCode": "WO",
"date": "2023-01-01T00:00:00.000Z"
},
{
"_id": "63b27787f6a8eccb2d95cf39",
"shiftCode": "HOBGS_1100",
"date": "2023-01-02T00:00:00.000Z",
"attendanceId": "63b236ef3980cffaf7715d69",
"inTime": "2023-01-02T07:14:08.000Z",
"attendanceDate": "2023-01-02T00:00:00.000Z",
"name": "name"
},
{
"_id": "63b277a2f6a8eccb2d95d400",
"shiftCode": "HOBGS_1100",
"date": "2023-01-03T00:00:00.000Z"
}
]
}
]
One option is to add one more step to your pipeline which finds for each shift item its matching item in attendances using $filter:
{$set: {
shiftListData: {$map: {
input: "$shiftListData",
as: "shift",
in: {$mergeObjects: [
"$$shift",
{$ifNull: [
{$first: {
$filter: {
input: "$attendances",
cond: {$eq: ["$$this.Date", "$$shift.date"]}
}
}},
{}
]}
]}
}},
attendances: "$$REMOVE"
}}
See how it works on the playground example

Mongoose Aggregate how to sum 2 objects in 2 arrays in the same collection

Im trying to sum value inside of an array of credits and debts, but i'm getting wrong results(credits: 800 and debits: 8) it's 400 and 4. I dont know what I'm doing wrong.
my collection
{
"_id": "5ca2156960e3fa38a0087cd8",
"name": "Jan",
"data": "2019-01-01T02:00:00.000Z",
"__v": 18,
"credits": [
{
"_id": "5ca24eabbc5e01341c034ecf",
"name": "cred 1",
"valor": 200
},
{
"_id": "5ca24ea9bc5e01341c034ece",
"name": "cred 2",
"valor": 200
},
],
"debits": [
{
"_id": "5ca230cffc553e36ec5841dd",
"name": "debit1",
"value": 2,
"status": "OK"
},
{
"_id": "5ca230cafc553e36ec5841dc",
"name": "debit2",
"value": 2,
"status": "OK"
}] }
Code:
db.collection.aggregate([
{ $unwind: '$credits' },
{ $unwind: '$debits' },
{$project: {
credits: { $sum: '$credits.value' },
debits: { $sum: '$debits.value' }}},
{
$group: {
_id: null,
credits: { $sum: '$credit' },
debits: { $sum: '$debits' }
}},
{$project: {
id: 0,
credits: 1,
debits: 1
}}])

Using aggregate $lookup and $mergeObjects

I want to join collection.
before, I used only lookup, so that I could get separated field that is joined.
but I need to get result similar mysql join.
I noticed there is $lookup and $mergeObjects for this action but not working well.
user collection model.
{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"name": 'admin user',
"email": 'admin#test.com',
"password": 'xxxxxxxx',
"roles": [
{
"id": 0,
"approved": true
},{
"id": 2,
"approved": true
}
]
},{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"name": 'userOne',
"email": 'user#test.com',
"password": 'xxxxxxxx',
"roles": [
{
"id": 1,
"approved": true
}
]
}
roles collection model.
{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"id": '0',
"name": 'administrator'
},{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"id": '0',
"name": 'employeer'
},{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"id": '0',
"name": 'freelancer'
}
after join, I want to get result like below.
{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"name": 'admin user',
"email": 'admin#test.com',
"password": 'xxxxxxxx',
"roles": [
{
"id": 0,
"name": "administrator", //join result
"approved": true
},{
"id": 2,
"name": "freelancer", //join result
"approved": true
}
]
},{
"_id": ObjectId("xxxxxxx"), //this is default id from mongoDB
"name": 'userOne',
"email": 'user#test.com',
"password": 'xxxxxxxx',
"roles": [
{
"id": 1,
"name": "employeer", //join result
"approved": true
}
]
}
You can use below aggregation with mongodb 3.4
You need to $unwind the roles array first and then $group to rollback again
db.users.aggregate([
{ "$unwind": "$roles" },
{ "$lookup": {
"from": "roles",
"localField": "roles.id",
"foreignField": "id",
"as": "roles.role"
}},
{ "$unwind": "$roles.role" },
{ "$addFields": {
"roles": { "$mergeObjects": ["$roles.role", "$roles"] }
}},
{ "$group": {
"_id": "$_id",
"email": { "$first": "$email" },
"password": { "$first": "$password" },
"roles": { "$push": "$roles" }
}},
{ "$project": { "roles.role": 0 }}
])
Which is quite simple with the mongodb 3.6 and above
db.users.aggregate([
{ "$unwind": "$roles" },
{ "$lookup": {
"from": "roles",
"let": { "roleId": "$roles.id", "approved": "$roles.approved" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$id", "$$roleId"] }}},
{ "$addFields": { "approved": "$$approved" }}
],
"as": "roles"
}},
{ "$unwind": "$roles" },
{ "$group": {
"_id": "$_id",
"email": { "$first": "$email" },
"password": { "$first": "$password" },
"roles": { "$push": "$roles" }
}}
])
Both will give you similar Output
[
{
"_id": ObjectId("5a934e000102030405000004"),
"email": "user#test.com",
"password": "xxxxxxxx",
"roles": [
{
"_id": ObjectId("5a934e000102030405000001"),
"approved": true,
"id": 1,
"name": "employeer"
}
]
},
{
"_id": ObjectId("5a934e000102030405000003"),
"email": "admin#test.com",
"password": "xxxxxxxx",
"roles": [
{
"_id": ObjectId("5a934e000102030405000000"),
"approved": true,
"id": 0,
"name": "administrator"
},
{
"_id": ObjectId("5a934e000102030405000002"),
"approved": true,
"id": 2,
"name": "freelancer"
}
]
}
]

$project field in MongoDB with dates conditional return empty

I need to return data with standard plains and plains with promotion if today's date is still within the period.
I have already managed to do almost everything, the only problem is that in $project, my condition is correct but returns empty.
Collection of course:
{
"_id": "58a4fcc8dddbeb0ba0a84ac8",
"updatedAt": "2017-02-16T10:26:37.841Z",
"createdAt": "2017-02-16T01:13:44.936Z",
"name": "Engenharia da computação",
"hours": 5000,
"AreaId": "58a4eec3aa912c63b241698d",
"PriceId": "58a4fbd3dddbeb0ba0a84ac0",
"ModalityId": "584e073edde7042be39b31a2",
"__v": 0,
"isActive": true
}
Collection of Price:
{
"_id": "58a4fbd3dddbeb0ba0a84ac0",
"description": "Preço de banana",
"__v": 0,
"promotions": [
{
"name": "Promoção de natal",
"rules": "Somente valido no notal",
"startsAt": "2017-01-16T17:12:26.289Z",
"expiresAt": "2017-07-16T17:12:26.289Z",
"_id": "58a4fbd3dddbeb0ba0a84ac1",
"isActive": false,
"plains": [
{
"parcels": 1,
"from": 1800,
"to": 1500,
"_id": "58a4fbd3dddbeb0ba0a84ac4"
},
{
"parcels": 2,
"from": 900,
"to": 800,
"_id": "58a4fbd3dddbeb0ba0a84ac3"
},
{
"parcels": 3,
"from": 400,
"to": 300,
"_id": "58a4fbd3dddbeb0ba0a84ac2"
}
]
}
],
"plains": [
{
"parcels": 1,
"from": 2000,
"to": 1600,
"_id": "58a4fbd3dddbeb0ba0a84ac7"
},
{
"parcels": 2,
"from": 1000,
"to": 999,
"_id": "58a4fbd3dddbeb0ba0a84ac6"
},
{
"parcels": 3,
"from": 500,
"to": 400,
"_id": "58a4fbd3dddbeb0ba0a84ac5"
}
]
}
I will receive from a form the parcels in number, example: '1 or 2 parcels'.
If this exists in the 'plains' documents in promotions, you should search, but you should check the dates if the promotion has not expired, otherwise you should look for default plains value.
This is my query:
Course
.aggregate([
{
$match: {
_id: ObjectId(req.body.CourseId)
}
},
{
$lookup: {
'from' : 'prices',
'localField' : 'PriceId',
'foreignField': '_id',
'as' : 'price'
}
},
{
$redact: {
$cond: {
if : {
$or: [
{$eq: ['$parcels', 1]},
{$or: '$price'},
{$or: '$promotions'},
{$or: '$plains'},
]
},
then: "$$DESCEND",
else: "$$PRUNE"
}
}
},
{
$project: {
promotions: {
$filter: {
input: "$price.promotions",
as : "promotion",
cond : {$and: [
{$lte: ["$$promotion.startsAt", new Date]},
{$gte: ["$$promotion.expiresAt", new Date]}
]}
}
},
plains : "$price.plains"
}
}
])
The return is this:
{
"_id": "58a4fcc8dddbeb0ba0a84ac8",
"promotions": [],
"plains": [
[
{
"parcels": 1,
"from": 2000,
"to": 1600,
"_id": "58a4fbd3dddbeb0ba0a84ac7"
}
]
]
}
Theoretically the array of promotions should not come empty, it's like this:
[
{
"name": "February Promotion",
"rules": "Valid only in February",
"startsAt": "2017-01-16T17:12:26.289Z",
"expiresAt": "2017-07-16T17:12:26.289Z",
"_id": "58a4fbd3dddbeb0ba0a84ac1",
"plains": [
{
"parcels": 1,
"from": 1800,
"to": 1500,
"_id": "58a4fbd3dddbeb0ba0a84ac4"
},
{
"parcels": 2,
"from": 900,
"to": 800,
"_id": "58a4fbd3dddbeb0ba0a84ac3"
},
{
"parcels": 3,
"from": 400,
"to": 300,
"_id": "58a4fbd3dddbeb0ba0a84ac2"
}
]
}
]
Thanks.

Categories