$out ,$projection in mongodb - node.js

i want to save records in a new collection using either $out or $merge.
**/////collection 2- reservationdeatils////**
"_id":ObjectId("5e4a898947363e964a886420"),
"phoneNo" : 98765#####,
"name" : "name1",
"userId":ObjectId("5e1efac668c3c811c83263cc"),
"approversId":ObjectId("5e1efad268c3c811c83263cd")
"bookedForDate":ISODate("2020-02-20T07:23:36.130Z"),
"bookingDetails" : [
{ "_id" : ObjectId("5e44f471d1868d2a54aac12d"),
"seatsBooked" : 15,
"floorId" : "#IKE01",
},
{ "_id" : ObjectId("5e44f471d1868d2a54aac12c"),
"seatsBooked" : 35,
"floorId" : "#HKE04",
}
],
**/////collection 2-priceDetails////**
{
"_id" : ObjectId("5e1efb0168c3c811c83263ce"),
"floorId" : "#IKE01",
"weekday" : "monday",
"pricePoint" : 589,
}
{
"_id" : ObjectId("5e2694db54e532a4eb92b477"),
"floorId" : "#IKE02",
"weekday" : "thursday",
"pricePoint" : 699
}
{
"_id" : ObjectId("5e2694f954e532a4eb92b478"),
"floorId" : "#HKE04",
"weekday" : "monday",
"pricePoint" : 579
}
**/////collection 3- discount////**
{
"_id" : ObjectId("5e427de64617181a4ce38893"),
"userId" : ObjectId("5e3d05ba964d0e06c4bb0f07"),
"approversId" : ObjectId("5e1d82156a67173cb877f67d"),
"floorId" : "#IKE01",
"weekday" : "monday",
"discount" : 20%,
},
{
"_id" : ObjectId("5e4281e7fec2e01a4c60b406"),
"userId" : ObjectId("5e1efac668c3c811c83263cc"),
"approversId" : ObjectId("5e1efad268c3c811c83263cd"),
"floorId" : "#IKE01",
"weekday" : "monday",
"discount" : 24%,
}
Now below is the query i have tried :
db.reservationdeatils.aggregate([
{
'$match': {
'approverId': ObjectId('5e1efad268c3c811c83263cd'),
'userId': ObjectId('5e1efac668c3c811c83263cc'),
'bookedForDate': ISODate("2020-02-11T18:30:00Z"),
}
},
{
'$unwind': {
'path': '$bookingDetails',
},
},
{
$lookup:
{
from: 'priceDetails',
let: { floorId: '$bookingDetails.floorId' },
pipeline: [
{
$match: {
weekday: 'monday',
$expr: {
$eq: ["$floorId", "$$floorId"]
}
}
}
], as: 'priceDetails'
}
},
{ '$unwind': '$priceDetails' },
{
$lookup:
{
from: 'discount',
let: { floorId: '$bookingDetails.floorId' },
pipeline: [
{
$match: {
weekday: 'monday',
$expr: {
$eq: ["$floorId", "$$floorId"]
}
}
}
], as: 'discounts'
}
},
{ '$unwind': '$discounts' },
{
'$group': {
'_id': {
'floorId': '$bookingDetails.floorId',
'date': '$bookedForDate',
'price': '$priceDetails.pricePoint',
'discount': '$discounts.discount'
},
'seatsBooked': {
'$sum': '$bookingDetails.seatsBooked'
},
}
},
{
'$project': {
'amount': {
'$multiply':
[
'$seatsBooked',
{'$subtract':
['$_id.pricePoint',
{ '$multiply':
['$_id.pricePoint',
{ '$divide':
['$_id.discount', 100]
}]
}]
}]
},
},
},
{
$group: {
_id: null,
totalAmount: {
$sum: "$amount"
}
}
},
{
'$project': {
_id:0,
totalAmount:1,
bookedForDate:1,
'floorId':'$priceDetails.floorId'
}
},{'$merge':'invoice'}
]).pretty()
i have been able to achieve the totalAmount but what i want to achieve is that i want to save these fields into "invoice" collection "userId","approversId","floorId","sum","totalSum","bookedForDate","name" BUT 1:whenever i use $out instead of $merge the previous document gets replaces which i dont want, 2: if i use $merge everytime i run the query a new document is created and that too only with _id:ObjectId(5e4a899c47363e964a88642f),totalBill:#### these fields , any suggestion how can i achieve this

You are going in a good direction you just need to look at the $group aggregation.
One more thing I have used the discount as int value, not in percentage.
"discount" : 24
I have updated the query:
db.reservationdeatils.aggregate([
{
$match: {
"userId" : ObjectId("5e1efac668c3c811c83263cc"),
"approversId" : ObjectId("5e1efad268c3c811c83263cd"),
"bookedForDate" : ISODate("2020-02-20T07:23:36.130Z")
}
},
{
$unwind: {
path: "$bookingDetails",
},
},
{
$lookup:
{
from: "priceDetails",
let: { floorId: "$bookingDetails.floorId" },
pipeline: [
{
$match: {
weekday: "monday",
$expr: {
$eq: ["$floorId", "$$floorId"]
}
}
}
],
as: "priceDetails"
}
},
{
$unwind: "$priceDetails"
},
{
$lookup:
{
from: "discount",
let: { floorId: "$bookingDetails.floorId" },
pipeline: [
{
$match: {
weekday: "monday",
$expr: {
$eq: ["$floorId", "$$floorId"]
}
}
}
],
as: "discounts"
}
}
,
{
$unwind: "$discounts"
}
,
{
$group: {
"_id": {
"floorId": "$bookingDetails.floorId",
"date": "$bookedForDate",
"price": "$priceDetails.pricePoint",
"discount": "$discounts.discount"
},
"price":{
$first:"$priceDetails.pricePoint"
},
"discount":{
$first:"$discounts.discount"
},
"seatsBooked": {
$sum: "$bookingDetails.seatsBooked"
},
}
}
,
{
$project: {
"amount": {
$multiply:
[
"$seatsBooked",
{
$subtract:[
"$price",
{
$multiply:[
"$price",
{
$divide:[
"$discount",
100
]
}
]
}
]
}
]
},
},
}
,
{
$group: {
"_id": null,
"totalAmount": {
$sum: "$amount"
}
}
},
{
$project: {
"_id":0,
"totalAmount":1,
"bookedForDate":1,
"floorId":"$priceDetails.floorId"
}
},
{
$out:"invoice"
}
]).pretty()
This will help you.

Related

Get Total Count using aggregate + facet using Mongo

I want to group my data based on event date with pagination. However what i am getting is whole record totalcount instead of eventDate count. because of this UI part is not working properly. Here is my collection sample:
{
"_id" : ObjectId("5fc4d0009a25e8cfbe306381"),
"eventDate" : ISODate("2021-11-29T01:00:00.000Z"),
"team1" : {
"tName" : "Chicago Bears",
},
"team2" : {
"tName" : "Green Bay Packers",
}
}
{
"_id" : ObjectId("5fc4d0019a25e8cfbe3063ff"),
"eventDate" : ISODate("2021-11-30T01:00:00.000Z"),
"team1" : {
"tName" : "Nashville SC",
},
"team2" : {
"tName" : "Columbus Crew",
}
}
{
"_id" : ObjectId("5fc4d0019a25e8cfbe3063f4"),
"eventDate" : ISODate("2021-11-30T01:00:00.000Z"),
"team1" : {
"tName" : "yyyy",
},
"team2" : {
"tName" : "xxxx",
}
}
here is my query:
db.getCollection('game').aggregate([
{ $addFields: { "newEventDate": {$dateToString:{ format: "%Y-%m-%d", date: "$eventDate" }}}},
{ "$match": {
"eventDate": { $gte: new Date() }
}
},
{ "$facet": {
"resultData": [
{ "$match": {
"eventDate": { $gte: new Date() }
}
},
{ "$group": {
"_id": "$newEventDate",
"games": {$push: {
team1:"$team1",
team2:"$team2"
}}
}
},
{ $sort: {eventDate: 1} },
{
$limit: 1
}
],
"pageInfo": [
{ "$count": "totalRecords" }
]}
}
]);
After executing this query this is my response:
{
"resultData" : [
{
"_id" : "2021-11-29",
"games" : [
{
"awayTeam" : {
"tName" : "Chicago Bears"
},
"homeTeam" : {
"tName" : "Green Bay Packers"
}
},
]
}
],
"pageInfo" : [
{
"totalRecords" : 3 **[here i want 2 ie total event date]**
}
]
}
$match your condition
move your $group stage outside from $facet, convert your date from string inside group, add you date in group stage because we are going to sort in next stage
$sort by eventDate ascending order
$facet, first get single record using $limit, and second part get total count of the record using $count
db.collection.aggregate([
{ $match: { eventDate: { $gte: new Date() } } },
{
$group: {
_id: {
$dateToString: {
format: "%Y-%m-%d",
date: "$eventDate"
}
},
eventDate: { $first: "$eventDate" },
games: {
$push: {
team1: "$team1",
team2: "$team2"
}
}
}
},
{ $sort: { eventDate: 1 } },
{
$facet: {
resultData: [{ $limit: 1 }],
pageInfo: [{ $count: "totalRecords" }]
}
}
])
Playground

deep mongodb aggregate to make Groups with the common fields in array of objects?

I want to make the groups from this using mongodb aggregate. I want to immplement this on my project but stuck in this. not finding a better way to do this.
{
"_id" : ObjectId("5e9a21868ed974259c0da402"),
"shopId" : "5e975cc7be7c1b546b7abb17",
"shopType" : "Medium Store",
"products": [{
"isPackedProduct" : true,
"_id" : ObjectId("5e92ff706af877294d63098e"),
"brand" : "ABC",
"category" : "CAT1",
"productName" : "P1",
"subCategory" : "SUB1",
},
{
"isPackedProduct" : true,
"_id" : ObjectId("5e92ff706af877294d63098f"),
"brand" : "EFG",
"category" : "CAT1",
"productName" : "P2",
"subCategory" : "SUB2",
},
{
"isPackedProduct" : true,
"_id" : ObjectId("5e92ff706af84d630977298f"),
"brand" : "EFG",
"category" : "CAT2",
"productName" : "P3",
"subCategory" : "SUB1",
}
....
]
}
From this set of json i want to show the data as:
{
"_id" : ObjectId("5e9a21868ed974259c0da402"),
"shopId" : "5e975cc7be7c1b546b7abb17",
"CAT1":{
"SUB1":{
"products": [{
...ALL the Products which have CAT1 and SUB1
}]
}
},
"CAT2":{
"SUB1":{
"products": [{
...ALL the Products which have CAT2 and SUB1
}]
}
}
...
}
i tried so far but not getting close to solution:
db.shopproducts.aggregate([{$unwind: {path: '$products'}}, {$group: {_id: 'products.category'}}, {$project: {'products.category': 1, 'products.productName': 1}}])
Also, if there is a better way to do this without using aggregate then suggestions are welcome.
Thanks in advance.
We need to apply several $group stages. To transform products.category and products.subCategory into object field, we need to use $arrayToObject operator.
[ {
{ "k" : "CAT1", "v" : "SUB1" }, ----\ "CAT1" : "SUB1",
{ "k" : "CAT2", "v" : "SUB1" } ----/ "CAT2" : "SUB1"
] }
Try this one:
db.shopproducts.aggregate([
{
$unwind: "$products"
},
{
$group: {
_id: {
_id: "$_id",
shopId: "$shopId",
category: "$products.category",
subCategory: "$products.subCategory"
},
products: {$push: "$products"}
}
},
{
$group: {
_id: {
_id: "$_id._id",
shopId: "$_id.shopId",
category: "$_id.category"
},
products: {
$push: {
k: "$_id.subCategory",
v: {products: "$products"}
}
}
}
},
{
$group: {
_id: {
_id: "$_id._id",
shopId: "$_id.shopId"
},
products: {
$push: {
k: "$_id.category",
v: {$arrayToObject: "$products"}
}
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
{
_id: "$_id._id",
shopId: "$_id.shopId"
},
{
$arrayToObject: "$products"
}
]
}
}
}
])
MongoPlayground
db.shopproducts.aggregate([
{
$unwind: {
path: "$products"
}
},
{
$group: {
_id: {
cat: "$products.category",
sub_cat: "$products.subCategory"
},
products: {
$addToSet: "$products"
}
}
}
])
I guess this is what you want, isn't it?
Mongoplayground

mongodb update query in aggregation from multiple collections without grouping

can i update specific fields in a particular collection according to the matched keys from different collections i.e suppose i have 3 collections
**///collection 1: col1///**
_id:ObjectId("#####7b")
name:'name1',
itemsBought:
[
{
"_id":ObjectId("####c1"
"itemName" : "name1",
"itemCode" : "IT001",
"itemQuantity" : 19,
"itemPrediction":23
},
{
"_id":ObjectId("####c2"
"itemName" : "name2",
"itemCode" : "IT002",
"itemQuantity" : 79,
"itemPrediction":69
},
{
"_id":ObjectId("####c3"
"itemName" : "name2",
"itemCode" : "IT003",
"itemQuantity" : 0,
"itemPrediction":0
},
]
**///collection 1: col2///**
{
"itemQuantity" : 21,
"itemCode" : "IT001",
},
{
"itemQuantity" : 2,
"itemCode" : "IT003",
}
**///collection 1: col3///**
{
"itemCode" : "IT001",
"itemPrediction":23
},
{
"itemCode" : "IT002",
"itemPrediction":12
},
{
"itemCode" : "IT003",
"itemPrediction":7
},
i am using $aggregation $lookup to fetch out all the required data, before sending it to the frontend i need to fetch the values of itemQuantity from col2 and itemPrediction from col3 and update that in col1 with the matching itemCode. So i have the query which fetches out all the data from all the collections but i dont know how to use $set to update the values in col1.
Workaround: You may perform aggregation and save the result manually
db.col1.aggregate([
{
$lookup: {
from: "col2",
let: {
root_itemCode: "$itemsBought.itemCode"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$itemCode",
"$$root_itemCode"
]
}
}
}
],
as: "col2"
}
},
{
$lookup: {
from: "col3",
let: {
root_itemCode: "$itemsBought.itemCode"
},
pipeline: [
{
$match: {
$expr: {
$in: [
"$itemCode",
"$$root_itemCode"
]
}
}
}
],
as: "col3"
}
},
{
$addFields: {
itemsBought: {
$map: {
input: "$itemsBought",
as: "item",
in: {
"_id": "$$item._id",
"itemName": "$$item.itemName",
"itemCode": "$$item.itemCode",
"itemQuantity": {
$let: {
vars: {
input: {
$arrayElemAt: [
{
$filter: {
input: "$col2",
cond: {
$eq: [
"$$item.itemCode",
"$$this.itemCode"
]
}
}
},
0
]
},
default: "$$item.itemQuantity"
},
in: {
$ifNull: [
"$$input.itemQuantity",
"$$default"
]
}
}
},
"itemPrediction": {
$let: {
vars: {
input: {
$arrayElemAt: [
{
$filter: {
input: "$col3",
cond: {
$eq: [
"$$item.itemCode",
"$$this.itemCode"
]
}
}
},
0
]
},
default: "$$item.itemPrediction"
},
in: {
$ifNull: [
"$$input.itemPrediction",
"$$default"
]
}
}
}
}
}
}
}
},
{
$unset: [
"col2",
"col3"
]
}
])
MongoPlayground
Mongoose
Collection1.aggregate([...], function (err, result) {
if(err) console.log("error-agg: " + err);
result.forEach(function(item) {
Collection1.updateOne({_id:item._id}, {$set:item}, function (err) {
if(err) console.log("error-saving: " + err);
});
});
});

query working in mongoshell but not in nodejs

Hi below is the description of the issue i am facing
mongoShell query
db.masters.aggregate([
{
$match: {
_id: ObjectId("5e2554ec3405363bc4bf86c0")
}
}, {
$lookup: {
from: 'masters',
localField: 'mappedVendors',
foreignField: '_id',
as: 'mappedVendors'
}
}, { $unwind: '$mappedVendors'}, { $replaceRoot: { newRoot: "$mappedVendors" } },
{
$lookup:
{
from: "orders",
let: { mappedVendorId: "$_id" },
pipeline: [
{
$match: { $expr: { $eq: ["$orderCreatedBy", "$$mappedVendorId"] } }
},
{ $project: { orderCreatedOn: 1, isApproved: 1 } }
],
as: "orders"
}
},{
$lookup:
{
from: "payments",
let: { mappedVendorId: "$_id" },
pipeline: [
{
$match: { $expr: { $eq: ["$paymentDoneBy", "$$mappedVendorId"] } }
},
{ $project: { outstanding: 1 } }
],
as: "payments"
}
},
{ $project: { name: 1, phoneNo: 1, address: 1, depotCode: 1, orders: 1, payments: 1 } }
]).pretty()
response i am getting in mongoshell
{
"_id" : ObjectId("5e2555643405363bc4bf86c4"),
"phoneNo" : 9992625541,
"name" : "vendor4",
"address" : "4 vendor address 4",
"depotCode" : "D3139",
"orders" : [ ],
"payments" : [
{
"_id" : ObjectId("5dd7aa6c31eb913a4c4a487c"),
"outstanding" : 300
}
]
}
{
"_id" : ObjectId("5e2555783405363bc4bf86c5"),
"phoneNo" : 9992625542,
"name" : "vendor5",
"address" : "5 vendor address 5",
"depotCode" : "D3139",
"orders" : [
{
"_id" : ObjectId("5e2564323405363bc4bf86c6"),
"isApproved" : false,
"orderCreatedOn" : ISODate("2020-01-20T08:26:26.812Z")
},
{
"_id" : ObjectId("5e27fd3da42d441fe8a89580"),
"isApproved" : false,
"orderCreatedOn" : ISODate("2020-01-15T18:30:00Z")
}
],
This query in shell is working as expected in shell but when i am trying this in nodejs its returning empty[].
below is the description of my nodejs file
1: Mongodb Connection string
const mongoose = require('mongoose')
mongoose.connect('mongodb://127.0.0.1:27017/#####App', {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify:false,
useUnifiedTopology: true
})
NOTE: ##### is not my code
2:nodejs controller
exports.vendorWiseIndent = async (req, res) => {
const { dealerId } = req.body
try {
const order = await Master.aggregate([
{
$match: {
_id: mongoose.Types.ObjectId(dealerId)
}
}, {
$lookup: {
from: "masters",
localField: "mappedVendors",
foreignField: "_id",
as: "mappedVendors"
},
},
{ $unwind: "$mappedVendors" }, { $replaceRoot: { newRoot: "$mappedVendors" } },
{
$lookup:
{
from: "orders",
let: { mappedVendorId: "$_id" },
pipeline: [
{
$match: { $expr: { $eq: ["$orderCreatedBy", "$$mappedVendorId"] } }
},
{ $project: { orderCreatedOn: 1, isApproved: 1 } }
],
as: "orders"
}
}, {
$lookup:
{
from: "payments",
let: { mappedVendorId: "$_id" },
pipeline: [
{
$match: { $expr: { $eq: ["$paymentDoneBy", "$$mappedVendorId"] } }
},
{ $project: { outstanding: 1 } }
],
as: "payments"
}
},
{ $project: { name: 1, phoneNo: 1, address: 1, depotCode: 1, orders: 1, payments: 1 } }
])
console.log(order)
return res.status(200).json({
order
});
} catch (error) {
res.send(error);
}}
I have also tried it with just {_id: dealerId}
3"nodejs router file
router.post("/vendorwiseindent", vendorWiseIndent.vendorWiseIndent);
POSTMAN BODY & url
POST: http://localhost:5002/vendorwiseindent
{
"dealerId": "5e2554ec3405363bc4bf86c0"
}
POSTMAN RESPONSE:
{
"order": []
}
I have also tried it with just{ _id: dealerId}
now mongodb database contains multiple collections and i have already other API's running so the db which is connected is right,there has to be some other issue that this query is not working in nodejs or rather its returning an empty array as order:[] but the query is working in shell
"mongoose": "5.7.4" & mongodb version is 4.2
nodejs controller files need be checked,
ADD
`const mongoose = require('mongoose ')`
at the top
dealerId was not getting converted to objectID as it was missing, after its addition POSTMAN response is mentioned below:
{
"order": [
{
"_id": "5e2555643405363bc4bf86c4",
"phoneNo": 9992625541,
"name": "vendor4",
"address": "4 vendor address 4",
"depotCode": "D3139",
"orders": [],
"payments": [
{
"_id": "5dd7aa6c31eb913a4c4a487c",
"outstanding": 300
}
]
},
{
"_id": "5e2555783405363bc4bf86c5",
"phoneNo": 9992625542,
"name": "vendor5",
"address": "5 vendor address 5",
"depotCode": "D3139",
"orders": [
{
"_id": "5e2564323405363bc4bf86c6",
"isApproved": false,
"orderCreatedOn": "2020-01-20T08:26:26.812Z"
},
{
"_id": "5e27fd3da42d441fe8a89580",
"isApproved": false,
"orderCreatedOn": "2020-01-15T18:30:00.000Z"
}
],
"payments": []
}
]
}

MongoDB/Mongoose - Querying an array of objects by date

I have the following metrics collection:
{
name: "Hello",
values: [
{
value: 2629,
date: "2016-10-28T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee8"
},
{
value: 1568,
date: "2016-10-29T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee7"
},
{
value: 1547,
date: "2016-10-30T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee6"
},
{
value: 1497,
date: "2016-10-31T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee5"
},
{
value: 3031,
date: "2016-11-01T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee4"
},
{
value: 2559,
date: "2016-11-02T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee3"
},
{
value: 2341,
date: "2016-11-03T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee2"
},
{
value: 2188,
date: "2016-11-04T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee1"
},
{
value: 3280,
date: "2016-11-05T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdee0"
},
{
value: 4638,
date: "2016-11-06T07:00:00.000Z",
_id: "58453abfef7aaa15ac1fdedf"
}
]
},
.... more of the same
What I would like to get is all the values between a custom date range.
I've tried the following query but I still get the entire values array returned:
{
name: "Hello",
values: {
$elemMatch: {
date: {
$lt: "2016-11-03T07:00:00.000Z",
$gt: "2016-10-28T07:00:00.000Z"
}
}
}
}
Maybe I saved my dates in a wrong format ? Any help would be greatly appreciated.
You can run an aggregation pipeline that uses the $filter operator on the values array. The following mongo shell query demonstrates this:
var start = new Date("2016-10-28T07:00:00.000Z"),
end = new Date("2016-11-03T07:00:00.000Z");
db.metrics.aggregate([
{
"$match": {
"name": "Hello",
"values.date": { "$gt": start, "$lt": end }
}
},
{
"$project": {
"name": 1,
"values": {
"$filter": {
"input": "$values",
"as": "value",
"cond": {
"$and": [
{ "$gt": [ "$$value.date", start ] },
{ "$lt": [ "$$value.date", end ] }
]
}
}
}
}
}
])
Sample Output
/* 1 */
{
"_id" : ObjectId("5845453145fda1298fa50db9"),
"name" : "Hello",
"values" : [
{
"value" : 1568,
"date" : ISODate("2016-10-29T07:00:00.000Z"),
"_id" : ObjectId("58453abfef7aaa15ac1fdee7")
},
{
"value" : 1547,
"date" : ISODate("2016-10-30T07:00:00.000Z"),
"_id" : ObjectId("58453abfef7aaa15ac1fdee6")
},
{
"value" : 1497,
"date" : ISODate("2016-10-31T07:00:00.000Z"),
"_id" : ObjectId("58453abfef7aaa15ac1fdee5")
},
{
"value" : 3031,
"date" : ISODate("2016-11-01T07:00:00.000Z"),
"_id" : ObjectId("58453abfef7aaa15ac1fdee4")
},
{
"value" : 2559,
"date" : ISODate("2016-11-02T07:00:00.000Z"),
"_id" : ObjectId("58453abfef7aaa15ac1fdee3")
}
]
}
For MongoDB 3.0, the following workaround applies:
var start = new Date("2016-10-28T07:00:00.000Z"),
end = new Date("2016-11-03T07:00:00.000Z");
db.metrics.aggregate([
{
"$match": {
"name": "Hello",
"values.date": { "$gt": start, "$lt": end }
}
},
{
"$project": {
"name": 1,
"values": {
"$setDifference": [
{
"$map": {
"input": "$values",
"as": "value",
"in": {
"$cond": [
{
"$and": [
{ "$gt": [ "$$value.date", start ] },
{ "$lt": [ "$$value.date", end ] }
]
},
"$$value",
false
]
}
}
},
[false]
]
}
}
}
])
The Aggregation Framework in MongoDB 2.2+ provides an alternative to Map/Reduce. The $unwind operator can be used to separate your values array into a stream of documents that can be matched:
db.tmp.aggregate(
// Start with a $match pipeline which can take advantage of an index and limit documents processed
{ $match : {
name: "Hello",
"values.date": {
$lt: "2016-11-03T07:00:00.000Z",
$gt: "2016-10-28T07:00:00.000Z" }
}},
{ $unwind : "$values" },
{ $match : {
name: "Hello",
"values.date": {
$lt: "2016-11-03T07:00:00.000Z",
$gt: "2016-10-28T07:00:00.000Z" }
}}
)
Sample output:
{
"_id":ObjectId("5845432720ce37bdc7e9ca1c"),
"name":"Hello",
"values":{
"value":1568,
"date":"2016-10-29T07:00:00.000Z",
"_id":"58453abfef7aaa15ac1fdee7"
}
},{
"_id":ObjectId("5845432720ce37bdc7e9ca1c"),
"name":"Hello",
"values":{
"value":1547,
"date":"2016-10-30T07:00:00.000Z",
"_id":"58453abfef7aaa15ac1fdee6"
}
},{
"_id":ObjectId("5845432720ce37bdc7e9ca1c"),
"name":"Hello",
"values":{
"value":1497,
"date":"2016-10-31T07:00:00.000Z",
"_id":"58453abfef7aaa15ac1fdee5"
}
},{
"_id":ObjectId("5845432720ce37bdc7e9ca1c"),
"name":"Hello",
"values":{
"value":3031,
"date":"2016-11-01T07:00:00.000Z",
"_id":"58453abfef7aaa15ac1fdee4"
}
},{
"_id":ObjectId("5845432720ce37bdc7e9ca1c"),
"name":"Hello",
"values":{
"value":2559,
"date":"2016-11-02T07:00:00.000Z",
"_id":"58453abfef7aaa15ac1fdee3"
}
}

Resources