Related
I have written a small query to get data from two collections,
here is my query as you can see:
Customer.aggregate([
{
$lookup: {
from: "Product",
localField: "product",
foreignField: "_id",
as: "productdata"
}
}
]).exec(function (err, res) {
if (err) {
console.log('Error', err)
}
else {
console.log(res);
}
});
I am always getting below output:
{
_id: 605412b063db104dfcb3d78a,
updated_at: 2021-03-19T02:55:44.098Z,
name: 'bhavesh',
product: '6052c356a76d435cf857aa3c',
city: 'surat',
__v: 0,
productdata: []
},
My collections are as follow:
// Customer collection
{
"_id": ObjectId("6052c3e50016c24b24a37f4d"),
"updated_at": ISODate("2021-03-18T08:37:17.659+05:30"),
"name": "bhavesh",
"product": "6052c356a76d435cf857aa3c",
"city": "surat"
},
{
"_id": ObjectId("6052c40202dce351e8448441"),
"updated_at": ISODate("2021-03-18T08:37:46.184+05:30"),
"name": "alex",
"product": "6052c369b9395c55042373e6",
"city": "ahmdabad"
},
{
"_id": ObjectId("6052c4157d1616563c707732"),
"updated_at": ISODate("2021-03-18T08:38:05.935+05:30"),
"name": "lexa",
"product": "6052c37321b64b4c40ac65a5",
"city": "mumbai"
},
{
"_id": ObjectId("6052c42efa94db04ccf19560"),
"updated_at": ISODate("2021-03-18T08:38:30.411+05:30"),
"name": "bhumi",
"product": "6052c37ef633e64cb8b65423",
"city": "surat"
}
// Product collection
{
"_id": ObjectId("6052c356a76d435cf857aa3c"),
"updated_at": ISODate("2021-03-18T08:34:54.187+05:30"),
"name": "laptop",
"company": "6052c217a1abc325b01ec87c",
"price": 66
},
{
"_id": ObjectId("6052c369b9395c55042373e6"),
"updated_at": ISODate("2021-03-18T08:35:13.939+05:30"),
"name": "charger",
"company": "6052c2311993dc433c0657d7",
"price": 50
},
{
"_id": ObjectId("6052c37321b64b4c40ac65a5"),
"updated_at": ISODate("2021-03-18T08:35:23.503+05:30"),
"name": "tablet",
"company": "6052c2311993dc433c0657d7",
"price": 50
},
{
"_id": ObjectId("6052c37ef633e64cb8b65423"),
"updated_at": ISODate("2021-03-18T08:35:34.979+05:30"),
"name": "bettery",
"company": "6052c217a1abc325b01ec87c",
"price": 500
}
// company collection
{
"_id": ObjectId("6052c217a1abc325b01ec87c"),
"updated_at": ISODate("2021-03-18T08:29:35.387+05:30"),
"name": "artoon",
"status": "active"
},
{
"_id": ObjectId("6052c2311993dc433c0657d7"),
"updated_at": ISODate("2021-03-18T08:30:01.508+05:30"),
"name": "identix",
"status": "active"
}
So basically I want data from 3 collections which have unique relation if you need more description please comment.
The $lookup doesn't match anything is because the localField 'product' of Customer collection is type String and the foreignField _id of Product collection is type ObjectId. The 2 values are not the same even though the look the same from your post. Notice that the _id value doesn't have the single quote around it while other fields (product and company) do.
You need to make them all the same type in order for the search to match. That is making
product field in Customer collection ObjectId type
company field in Product collection ObjectId type
Try this query for performing join between 3 collections:
db.Customer.aggregate([
{
$lookup: {
from: "Product",
let: {
product_id: { $toObjectId: "$product" }
},
pipeline: [
{
$match: {
$expr: { $eq: ["$_id", "$$product_id"] }
}
},
{
$lookup: {
from: "company",
let: {
company_id: { $toObjectId: "$company" },
},
pipeline: [
{
$match: {
$expr: { $eq: ["$_id", "$$company_id"] }
}
}
],
as: "company"
}
},
{ $unwind: "$company" }
],
as: "Product"
}
},
{ $unwind: "$Product" }
]);
Output:
/* 1 createdAt:3/18/2021, 8:37:17 AM*/
{
"_id" : ObjectId("6052c3e50016c24b24a37f4d"),
"updated_at" : ISODate("2021-03-18T08:37:17.659+05:30"),
"name" : "bhavesh",
"product" : "6052c356a76d435cf857aa3c",
"city" : "surat",
"Product" : {
"_id" : ObjectId("6052c356a76d435cf857aa3c"),
"updated_at" : ISODate("2021-03-18T08:34:54.187+05:30"),
"name" : "laptop",
"company" : {
"_id" : ObjectId("6052c217a1abc325b01ec87c"),
"updated_at" : ISODate("2021-03-18T08:29:35.387+05:30"),
"name" : "artoon",
"status" : "active"
},
"price" : 66
}
},
/* 2 createdAt:3/18/2021, 8:37:46 AM*/
{
"_id" : ObjectId("6052c40202dce351e8448441"),
"updated_at" : ISODate("2021-03-18T08:37:46.184+05:30"),
"name" : "alex",
"product" : "6052c369b9395c55042373e6",
"city" : "ahmdabad",
"Product" : {
"_id" : ObjectId("6052c369b9395c55042373e6"),
"updated_at" : ISODate("2021-03-18T08:35:13.939+05:30"),
"name" : "charger",
"company" : {
"_id" : ObjectId("6052c2311993dc433c0657d7"),
"updated_at" : ISODate("2021-03-18T08:30:01.508+05:30"),
"name" : "identix",
"status" : "active"
},
"price" : 50
}
},
/* 3 createdAt:3/18/2021, 8:38:05 AM*/
{
"_id" : ObjectId("6052c4157d1616563c707732"),
"updated_at" : ISODate("2021-03-18T08:38:05.935+05:30"),
"name" : "lexa",
"product" : "6052c37321b64b4c40ac65a5",
"city" : "mumbai",
"Product" : {
"_id" : ObjectId("6052c37321b64b4c40ac65a5"),
"updated_at" : ISODate("2021-03-18T08:35:23.503+05:30"),
"name" : "tablet",
"company" : {
"_id" : ObjectId("6052c2311993dc433c0657d7"),
"updated_at" : ISODate("2021-03-18T08:30:01.508+05:30"),
"name" : "identix",
"status" : "active"
},
"price" : 50
}
},
/* 4 createdAt:3/18/2021, 8:38:30 AM*/
{
"_id" : ObjectId("6052c42efa94db04ccf19560"),
"updated_at" : ISODate("2021-03-18T08:38:30.411+05:30"),
"name" : "bhumi",
"product" : "6052c37ef633e64cb8b65423",
"city" : "surat",
"Product" : {
"_id" : ObjectId("6052c37ef633e64cb8b65423"),
"updated_at" : ISODate("2021-03-18T08:35:34.979+05:30"),
"name" : "bettery",
"company" : {
"_id" : ObjectId("6052c217a1abc325b01ec87c"),
"updated_at" : ISODate("2021-03-18T08:29:35.387+05:30"),
"name" : "artoon",
"status" : "active"
},
"price" : 500
}
}
I have the following query:
db.test.aggregate([
{
$match: {
'type': 'energy'
}
},
{
$limit: 10000
},
{
$addFields: {
day: {
$dateToString: {
date: "$when.date",
format: "%d/%m/%Y"
}
},
sensor: "$id"
},
},
{
$project: {
_id: 1,
sensor: 1,
when: 1,
value: 1,
day: 1
}
},
{
$group: {
_id: "$day",
data: {
$push: "$$ROOT"
},
}
},
{
$sort: {
'data': 1
}
}
])
Which returns this data format:
{
"_id" : "05/04/2018",
"data" : [
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c7"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.703-03:00"),
"unix" : 1522947202,
"milli" : 1522947202703
},
"day" : "05/04/2018",
"sensor" : "sen3"
},
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c8"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.705-03:00"),
"unix" : 1522947202,
"milli" : 1522947202705
},
"day" : "05/04/2018",
"sensor" : "sen4"
}
]
},
{
"_id" : "06/04/2018",
"data" : [
{
"_id" : ObjectId("5ac7e5d2efe88a4e76c008d2"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:25:38.885-03:00"),
"unix" : 1523049938,
"milli" : 1523049938885
},
"day" : "06/04/2018",
"sensor" : "sen3"
},
{
"_id" : ObjectId("5ac7e5e4efe88a4e76c008d5"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:25:56.105-03:00"),
"unix" : 1523049956,
"milli" : 1523049956105
},
"day" : "06/04/2018",
"sensor" : "sen3"
}
]
},
...
Note that we have in each "data" document, different types of sensors (sen3, sen4, ... ,senN).
I'm trying to aggregate this result once more, agrouping the data by sensor, to get the output something like this:
{
"_id" : "05/04/2018",
"sen3" : [
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c7"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.703-03:00"),
"unix" : 1522947202,
"milli" : 1522947202703
},
"day" : "05/04/2018",
"sensor" : "sen3"
},
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c7"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.703-03:00"),
"unix" : 1522947202,
"milli" : 1522947202703
},
"day" : "05/04/2018",
"sensor" : "sen3"
}
],
"sen4" : [
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c8"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.705-03:00"),
"unix" : 1522947202,
"milli" : 1522947202705
},
"day" : "05/04/2018",
"sensor" : "sen4"
},
{
"_id" : ObjectId("5ac66be9b02d5c18fd4106c8"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-05T13:53:22.705-03:00"),
"unix" : 1522947202,
"milli" : 1522947202705
},
"day" : "05/04/2018",
"sensor" : "sen4"
}
]
},
{
"_id" : "06/04/2018",
"sen3" : [
{
"_id" : ObjectId("5ac7e5d2efe88a4e76c008d2"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:25:38.885-03:00"),
"unix" : 1523049938,
"milli" : 1523049938885
},
"day" : "06/04/2018",
"sensor" : "sen3"
},
{
"_id" : ObjectId("5ac7e5e4efe88a4e76c008d5"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:25:56.105-03:00"),
"unix" : 1523049956,
"milli" : 1523049956105
},
"day" : "06/04/2018",
"sensor" : "sen3"
}
],
"sen4": [
{
"_id" : ObjectId("5ac7e7a7efe88a4e76c008de"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:33:27.365-03:00"),
"unix" : 1523050407,
"milli" : 1523050407365
},
"day" : "06/04/2018",
"sensor" : "sen4"
},
{
"_id" : ObjectId("5ac7e7a7efe88a4e76c008de"),
"value" : 0,
"when" : {
"date" : ISODate("2018-04-06T18:33:27.365-03:00"),
"unix" : 1523050407,
"milli" : 1523050407365
},
"day" : "06/04/2018",
"sensor" : "sen4"
}
]
}
In short: I want to group the data in days, sensors and inside each sensor the results that belongs with that day and sensor.
I'm trying to create a nested $group but in all tentatives it goes wrong.
Is this possible to do and case yes, how?
You can try below aggregation in mongodb 3.6 and above
db.collection.aggregate([
{ "$match": { "type": "energy" }},
{ "$limit": 10000 },
{ "$addFields": {
"day": { "$dateToString": { "date": "$when.date", "format": "%d/%m/%Y" }},
"sensor": "$id"
}},
{ "$project": { "_id": 1, "sensor": 1, "when": 1, "value": 1, "day": 1 }},
{ "$group": {
"_id": { "day": "$day", "sensor": "$sensor" },
"data": { "$push": "$$ROOT" }
}},
{ "$group": {
"_id": { "day": "$_id.day" },
"data": { "$push": { "k": "$_id.sensor", "v": "$data" }}
}},
{ "$addFields": { "data": { "$arrayToObject": "$data" }}},
{ "$replaceRoot": { "newRoot": { "$mergeObjects": [ "$_id", "$data" ] }}}
])
Here I'll show you what exactly I want. Suppose I have the below two document for XYZ model.
[
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"email" : "one#one.com",
"mobileNumber" : "910123456989",
"verificationStatus" : true,
"activities" : [
{
"name" : "a1",
"_id" : ObjectId("59ef8786e8c7d60552139bae"),
"type" : 0,
"level" : null,
"verificationStatus" : true
},
{
"name" : "a2",
"_id" : ObjectId("59ef8786e8c7d60552139bad"),
"type" : 0,
"level" : null,
"verificationStatus" : false
}
],
"address" : {
"line1" : "asd",
"line2" : "asd",
"city" : "sd",
"state" : "sd",
"country" : "asd",
"landmark" : "sdsa",
"pincode" : "560090"
},
"__v" : 0
},
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"email" : "one#one.com",
"mobileNumber" : "919876543210",
"verificationStatus" : true,
"activities" : [
{
"name" : "b1",
"_id" : ObjectId("59ef8786e8c7d60552139bae"),
"level" : null,
"type" : 0,
"verificationStatus" : true
},
{
"name" : "b2",
"_id" : ObjectId("59ef8786e8c7d60552139bad"),
"level" : null,
"type" : 0,
"verificationStatus" : false
}
],
"address" : {
"line1" : "asd",
"line2" : "asd",
"city" : "sd",
"state" : "sd",
"country" : "asd",
"landmark" : "sdsa",
"pincode" : "560090"
},
"__v" : 0
}
]
Now I want only the name, mobileNumber and activities.name from the document where verificationStatus is true and I don't want all the activities I want activities.name only if activities.varificationStatus is true.
I can get the list of all document where varificationStatus is true and activities.varificationStatus is true but I'm not able to select only required fields (activities.name) from activities.
My current code is:
XYZ.aggregate(
[
{ $match: { verificationStatus: true } },
{
$project: {
name: 1,
coverImage: 1,
location: 1,
address: 1,
dist: 1,
activities: {
$filter: {
input: "$activities",
as: "activity",
cond: {
$eq: ["$$activity.verificationStatus", true]
}
}
}
}
}], function (err, list) {
if (err) {
reject(err);
}
else {
resolve(list);
}
});
You actually need $map to "alter" the array elements returned, as $filter only "selects" the array elements that "match":
XYZ.aggregate(
[
{ $match: { verificationStatus: true } },
{
$project: {
name: 1,
mobileNumber: 1,
activities: {
$map: {
input: {
$filter: {
input: "$activities",
as: "activity",
cond: "$$activity.verificationStatus"
}
},
"as": "a",
"in": "$$a.name"
}
}
}
}], function (err, list) {
...
Would return:
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "910123456989",
"activities" : ["a1"]
}
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "919876543210",
"activities" : ["b1"]
}
Note also that the "cond" in $filter can be shortened since it's already a boolean value.
If you wanted the "object" with the property of "name" only, then return just that assigned key:
XYZ.aggregate(
[
{ $match: { verificationStatus: true } },
{
$project: {
name: 1,
mobileNumber: 1,
activities: {
$map: {
input: {
$filter: {
input: "$activities",
as: "activity",
cond: "$$activity.verificationStatus"
}
},
"as": "a",
"in": {
"name": "$$a.name"
}
}
}
}
}], function (err, list) {
...
Returns as:
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "910123456989",
"activities" : [{ "name": "a1" }]
}
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "919876543210",
"activities" : [{ "name": "b1" }]
}
If you knew for certain that you were matching "one" element in the array, then $indexOfArray with $arrayElemAt could be used instead if you have MongoDB 3.4
{ "$project": {
"name": 1,
"mobileNumber": 1,
"activities": {
"$arrayElemAt": [
"$activities.name",
{ "$indexOfArray": [ "$activities.verificationStatus", true ] }
]
}
}}
Which would come out a little differently since it's a singular value and not an array:
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "910123456989",
"activities" : "a1"
}
{
"_id" : ObjectId("59ef8786e8c7d60552139ba9"),
"name" : "s1",
"mobileNumber" : "919876543210",
"activities" : "b1"
}
This is my mongoose collection data:
{
"ShopId" : "439",
"productName" : "veg",
"productCategory" : "meals",
"mrp" : "38 "
},
{
"ShopId" : "439",
"productName" : "non-veg",
"productCategory" : "meals",
"mrp" : "380 "
},{....}
Query
db.getCollection('ProductDetails').aggregate(
[{ "$match": { "ShopId": "439" } },{"$group": {"_id": "$productCategory", "count": { "$sum": 1 },
"products": {"$push":{"productname": "$productName"}}}},
{"$group": {"_id": null, "productList": {"$push": {"categoryname": "$_id", "productcount": "$count",
"products": "$products"}}}},{$project:{products:{$slice:["$productList.products",2]}}}])
Output:
{
"_id" : null,
"productList" : [
{
"categoryname" : "meals",
"productcount" : 8.0,
"products" : [
{
"productname" : "non veg"
},
{
"productname" : "veg"
},
{
"productname" : "c"
},
{
"productname" : "d"
},
{
"productname" : "df"
},
{
"productname" : "dfr"
},
{
"productname" : "qe"
},
{
"productname" : "as"
}
]
}
]
}
expected output:
I want to limit the number of products to 2.But instead of that all products are displaying.
{
"_id" : null,
"productList" : [
{
"categoryname" : "meals",
"productcount" : 8.0,
"products" : [
{
"productname" : "non veg"
},
{
"productname" : "veg"
}
]
}
]
}
Replace your $project stage with below.
{$project:{products:{$slice:[{$arrayElemAt:["$productList.products", 0]},2]}}}
Your products is array of arrays.
"products": [
[{
"productname": "veg"
}, {
"productname": "non-veg"
}]
]
$arrayElemAt with 0 will pick the inner array and you can use $slice to limit the products.
I believe you are using the $slice function wrong: As I mentioned in this post:
Find a value in array
The slice function takes two parameters: The first is the initial index and the second is the number of elements after this index. Here's an example:
db.collection.find({},{_id:0,products:{$slice : [0,2]})
This will take two elements from the index [0] of the array. Hope my answer was helpful.
From the MongoDB doc for $elementMatch:
The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
But how can I match documents that contain an array field with ALL elements that match the query?
For example I have documents like this:
{
"_id": ObjectId("55c99649b8b5fc5b0a2f1c83"),
"sku": "ed-39211",
"created_at": ISODate("2015-08-11T06:29:29.139+0000"),
"formats": [{
"name": "thefile",
"_id": ObjectId("55c99649f2e2d6353348ec9c"),
"prices": [{
"price": 4.49,
"currency": "GBP",
"territory": "GB",
"_id": ObjectId("55c99649f2e2d6353348ec9f")
}, {
"price": 6.99,
"currency": "USD",
"territory": "US",
"_id": ObjectId("55c99649f2e2d6353348ec9e")
}, {
"price": 6.99,
"currency": "CHF",
"territory": "CH",
"_id": ObjectId("55c99649f2e2d6353348ec9d")
}]
}]
}
And I need to match all documents that have all the formats.prices.price > 5
If I use the following query:
{ 'formats.prices': { $elemMatch: { price: { $gte: 5 } } } }
That document will be matched because there is at least one price > 5
I also tried this but it doesn't seem to work:
{ 'formats.prices': { $all: { $elemMatch: {price: { $gte: 0.98 } } } } }
Is there a way to exclude that document looking at all prices an not at least one?
Found it! It was easy, just use $notoperator and check the opposite (< 5):
{ 'formats.prices': { $not: { $elemMatch: {price: { $lt: 5 } } } } }
You Can use Aggegation OR MAP REDUCE to achieve it :
First solution is using Map-Reduce :
I created a collection called "format" and inserted below data :
{
"_id" : ObjectId("55c99649b8b5fc5b0a2f1c83"),
"sku" : "ed-39211",
"created_at" : ISODate("2015-08-11T06:29:29.139Z"),
"formats" : [
{
"name" : "thefile",
"_id" : ObjectId("55c99649f2e2d6353348ec9c"),
"prices" : [
{
"price" : 4.49,
"currency" : "GBP",
"territory" : "GB",
"_id" : ObjectId("55c99649f2e2d6353348ec9f")
},
{
"price" : 6.99,
"currency" : "USD",
"territory" : "US",
"_id" : ObjectId("55c99649f2e2d6353348ec9e")
},
{
"price" : 6.99,
"currency" : "CHF",
"territory" : "CH",
"_id" : ObjectId("55c99649f2e2d6353348ec9d")
}
]
}
]
}
{
"_id" : ObjectId("55c99649b8b5fc5b0a2f1c84"),
"sku" : "ed-39211",
"created_at" : ISODate("2015-08-11T06:29:29.139Z"),
"formats" : [
{
"name" : "thefile",
"_id" : ObjectId("55c99649f2e2d6353348ec9a"),
"prices" : [
{
"price" : 5.49,
"currency" : "GBP",
"territory" : "GB",
"_id" : ObjectId("55c99649f2e2d6353348ec9f")
},
{
"price" : 6.99,
"currency" : "USD",
"territory" : "US",
"_id" : ObjectId("55c99649f2e2d6353348ec9e")
},
{
"price" : 6.99,
"currency" : "CHF",
"territory" : "CH",
"_id" : ObjectId("55c99649f2e2d6353348ec9d")
}
]
}
]
}
Map_reduce :
db.format.mapReduce(
function()
{
var doc = {"_id" : this._id, "sku" : this.sku, "created_at" : this.created_at, "formats" : this.formats};
var prices;
var flag = 0;
for ( var i = 0 ; i < doc.formats.length; i++)
{
prices = doc.formats[i].prices
for ( var j =0 ; j < prices.length; j++)
{
if( prices[j].price < 5)
{
flag = 1;
break;
}
}
if( flag == 1)
doc.formats.splice(i,1);
}
if( doc.formats.length > 0 )
emit( this._id, doc);
},
function(){},
{ "out": { "inline": 1 } }
)
Output :
{
"results" : [
{
"_id" : ObjectId("55c99649b8b5fc5b0a2f1c84"),
"value" : {
"_id" : ObjectId("55c99649b8b5fc5b0a2f1c84"),
"sku" : "ed-39211",
"created_at" : ISODate("2015-08-11T06:29:29.139Z"),
"formats" : [
{
"name" : "thefile",
"_id" : ObjectId("55c99649f2e2d6353348ec9a"),
"prices" : [
{
"price" : 5.49,
"currency" : "GBP",
"territory" : "GB",
"_id" : ObjectId("55c99649f2e2d6353348ec9f")
},
{
"price" : 6.99,
"currency" : "USD",
"territory" : "US",
"_id" : ObjectId("55c99649f2e2d6353348ec9e")
},
{
"price" : 6.99,
"currency" : "CHF",
"territory" : "CH",
"_id" : ObjectId("55c99649f2e2d6353348ec9d")
}
]
}
]
}
Second Solution using Aggregation :
Using aggregate operators $unwind and $size we can get the required result using below query :
After $unwind of "Formats" and "Formats.prices", size of the "Formats.prices" is taken and then a $match on the "prices" is done and again the new size is calculated for "Formats.prices".
If the size are same then all the "prices" in the "format" field are greater than 5 and the document will be projected.
db.format.aggregate([
{ $unwind: "$formats" },
{ $project : { _id : 1, sku : 1, created_at : 1, formats : 1, "size" : { $size : "$formats.prices" } } },
{ $unwind: "$formats.prices" },
{ $match: { "formats.prices.price" : { $gt:5 } } },
{ $group: { _id: { "name" : "$formats.name" , "_id" : "$formats._id", "id" : "$_id" }, prices : { $push: "$formats.prices" } , sku: { $first: "$sku" }, created_at : { $first: "$created_at" }, oldsize : { $first: "$size" } } },
{ $project: { _id : 1, prices : 1, sku : 1, created_at : 1, oldsize : 1, newsize : {$size: "$prices" } } },
{ $project: { _id : 1, prices : 1, sku : 1, created_at : 1, cmp_value: { $cmp: ["$oldsize", "$newsize"] } } },
{ $match: { cmp_value:{ $eq:0 } } },
{ $group : { _id : "$_id.id" , sku: { $first: "$sku" }, created_at : { $first: "$created_at" }, formats : { $push: { name : "$_id.name", "_id" : "$_id._id", prices: "$prices" } } } }
]).pretty()
Output :
{
"_id" : ObjectId("55c99649b8b5fc5b0a2f1c84"),
"sku" : "ed-39211",
"created_at" : ISODate("2015-08-11T06:29:29.139Z"),
"formats" : [
{
"name" : "thefile",
"_id" : ObjectId("55c99649f2e2d6353348ec9a"),
"prices" : [
{
"price" : 5.49,
"currency" : "GBP",
"territory" : "GB",
"_id" : ObjectId("55c99649f2e2d6353348ec9f")
},
{
"price" : 6.99,
"currency" : "USD",
"territory" : "US",
"_id" : ObjectId("55c99649f2e2d6353348ec9e")
},
{
"price" : 6.99,
"currency" : "CHF",
"territory" : "CH",
"_id" : ObjectId("55c99649f2e2d6353348ec9d")
}
]
}
]
}