Select min value of a field with $min and aggregate in mongodb - node.js

I want to get document with all fields for the aggregation of $min with particular field in my collection.
Below is my collection structure,
{
"_id" : ObjectId("585e7454b0a2683a0f6a3617"),
"postid":100,
"region" : "IN",
"brand" : "Uber",
"used" : 4
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a35b7"),
"postid":101,
"region" : "UK",
"brand" : "Airbnb",
"used" : 7
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a3619"),
"postid":102,
"region" : "US",
"brand" : "Uber",
"used" : 9
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a3619"),
"postid":103,
"region" : "US",
"brand" : "Airbnb",
"used" : 2
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a3619"),
"postid":104,
"region" : "US",
"brand" : "Home",
"used" : 17
}
I want to get distinct value of brand of a document with $min value of 'used' field.
I want to get output like this,
{
"_id" : ObjectId("585e7454b0a2683a0f6a3617"),
"postid":100,
"region" : "IN",
"brand" : "Uber",
"used" : 4
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a3619"),
"postid":103,
"region" : "US",
"brand" : "Airbnb",
"used" : 2
}
{
"_id" : ObjectId("585e7454b0a2683a0f6a3619"),
"postid":104,
"region" : "US",
"brand" : "Home",
"used" : 17
}
Currently I am using this query for this,
db.sales.aggregate(
[
{
$group:
{
_id: "$brand",
used: { $min: "$used" }
}
}
]
);
Thanks in advance

If you want to include the other fields in the group, better use the $first or $last accumulators but after ordering your documents. In this case you'd want to use the $sort operator as your first pipeline step first then group afterwards with the documents in ascending order:
db.sales.aggregate([
{ "$sort": { "brand": 1, "used": 1 } },
{
"$group": {
"_id": "$brand",
"postid": { "$first": "$postid" },
"region": { "$first": "$region" },
"docId": { "$first": "$_id" },
"used": { "$first": "$used" }
}
}
])

Related

How to lookup and filter in array of objects mongo?

I have a question about lookup and filter array of objects in mongodb
I have structure: Person
{
"_id": "5cc3366c22c3767a2b114c6b",
"flags": [
"5cc30210fada5d7820d03aaf",
"5cc2c3924a94a575adbdc56a"
],
"key": "Animal",
"name": "name1",
"description": "description1",
"endpoints": [
{
"isEnabled": true,
"publishUrl": "megaUrl",
"env": "5cc1a8911b19026fd193506b"
},
{
"isEnabled": true,
"publishUrl": "megaUrl",
"env": "5ccaeef3312acb103730d4c5"
}
]
}
envs collection
{
"_id" : "5cc1a8911b19026fd193506b",
"name" : "name2",
"key" : "PROD",
"publishUrl" : "url1",
"__v" : 0
}
{
"_id" : "5ccaeef3312acb103730d4c5",
"name" : "name2",
"key" : "PROD",
"publishUrl" : "url1",
"__v" : 0
}
I should filter Document by endpoints.$.env
so, I have: accessKeys = ["PROD", "UAY"], and i should see result . with endpoints where env.key === "PROD" || env.key === "UAT"
Expected result:
{
"_id": "5cc3366c22c3767a2b114c6b",
"flags": [
"5cc30210fada5d7820d03aaf",
"5cc2c3924a94a575adbdc56a"
],
"key": "Animal",
"name": "name1",
"description": "description1",
"endpoints": [
{
"isEnabled": true,
"publishUrl": "megaUrl",
"env": {
"_id" : "5cc1a8911b19026fd193506b",
"name" : "name2",
"key" : "PROD",
"publishUrl" : "url1",
"__v" : 0
}
},
]
}
Help me pls, how i can do that? I know about aggregate, but cant do it :(
Try this :
db.persons.aggregate([{
$unwind : "$endpoints"
},{
$lookup :{
from : "envs",
localField : "endpoints.env",
foreignField : "_id",
as : "endpoints.env"
}
},{
$unwind : "$endpoints.env"
},{
$match : {
"endpoints.env.key" : {$in : accessKeys}
}
},{
$group : {
_id : "$_id",
flags : {$first : "$flags"},
key : {$first : "$key"},
name : {$first : "$name"},
description : {$first : "$description"},
endpoints : {$push : "$endpoints"},
}
}])

How to use $filter(aggregation) to select some fields of array only if condition true?

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"
}

slice in array not working?

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.

Mongo query not giving exact results for aggregate function

My mongo database contains a collection 'Shops' and the data is like below:
{
"_id" : ObjectId("XXXX1b83d2b227XXXX"),
"ShopId" : 435,
"products" : [
{
"productId" : "1234",
"productName" : "non veg",
"productCategory" : "meals",
"mrp" : "38",
},
{
"productId" : "5234",
"productName" : "non veg",
"productCategory" : "meals",
"mrp" : "38",
},
{
"productId" : "6234",
"productName" : "apple",
"productCategory" : "juice",
"mrp" : "38",
},
{
"productId" : "7234",
"productName" : "non veg",
"productCategory" : "biriyani",
"mrp" : "38",
},
{
"productId" : "8234",
"productName" : "non veg",
"productCategory" : "biriyani",
"mrp" : "38",
}
]
}
There will be several shops in the collection having a list of products.
Expected Output
{ "productList": [
{
"categoryname": "meals",
"productcount": "2",
"products": [
{
"productname": "Non-Veg"
},
{
"productname": "Veg"
}
]
},
{
"categoryname": "juice",
"productcount": "1",
"products": [
{
"productname": "apple"
}
]
},{......}
]
}
I tried it using 'async' method with 2 queries, but I didn't get the output correctly. I think it can be done in one query without using 'async'.
My code follows, I think it's the wrong approach:
model.Shops.aggregate([
{$match:{ShopId:435}},
{$unwind:"$products"},
{$limit:2},{$skip:0},
{$group:{_id:{"productCategory":"$products.productCategory"}}}
],function (err, doc) {
if (doc!=null){
var arr = [];
async.each(doc, function(item,callback){
model.Shops.aggregate([
{"$unwind":"$products"},
{$match:{"ShopId":435,"products.productCategory":item._id.productCategory}},
{$limit:2},
{
$group: {
_id:null,
"products": {
$push:{"productName":"$products.productName"}
}
}
}
], function (err,doc) {
arr.push({"categoryname":item._id.productCategory,"products":doc.products});
callback(null);
});
},function (err) {
res.json(arr);
});
}
});
You certainly do not need two queries for this, a single pipeline will suffice. Run the following aggregate operation to get the desired results:
model.Shops.aggregate([
{ "$match": { "ShopId": 435 } },
{ "$unwind": "$products" },
{
"$group": {
"_id": "$products.productCategory",
"count": { "$sum": 1 },
"products": {
"$push": {
"productName": "$products.productName"
}
}
}
},
{
"$group": {
"_id": null,
"productList": {
"$push": {
"categoryname": "$_id",
"productcount": "$count",
"products": "$products"
}
}
}
}
], function (err, results) {
res.json(results);
});
Explanations
The above pipeline uses the following pipeline steps (in the order given) and explained as:
Step 1) $match operator is there to filter documents that get into the pipeline. If you are coming from a SQL background, this pipeline is similar to the SQL's WHERE clause where e.g.
SELECT *
FROM Shops
WHERE ShopId = 435
If you run the pipeline at this stage only, it will return all the documents that match on the ShopId of 435
Step 2) $unwind - The products field is an array so you'll need to add an $unwind stage to your pipeline so that you can flatten the array as it needs to be processed further down as a denormalised field. For each input document, this outputs n documents where n is the number of array elements and can be zero for an empty array.
Running the aggregate pipeline up to this stage for the above sample will produce 5 documents i.e. in mongo shell
db.getCollection('shops').aggregate([
{ "$match": { "ShopId": 435 } }, // Step 1
{ "$unwind": "$products" } // Step 2
])
will yield
[
{
"_id" : ObjectId("58aadec0671a3794272f342f"),
"ShopId" : 435,
"products" : {
"productId" : "1234",
"productName" : "non veg",
"productCategory" : "meals",
"mrp" : "38"
}
},
{
"_id" : ObjectId("58aadec0671a3794272f342f"),
"ShopId" : 435,
"products" : {
"productId" : "5234",
"productName" : "non veg",
"productCategory" : "meals",
"mrp" : "38"
}
},
{
"_id" : ObjectId("58aadec0671a3794272f342f"),
"ShopId" : 435,
"products" : {
"productId" : "6234",
"productName" : "apple",
"productCategory" : "juice",
"mrp" : "38"
}
},
{
"_id" : ObjectId("58aadec0671a3794272f342f"),
"ShopId" : 435,
"products" : {
"productId" : "7234",
"productName" : "non veg",
"productCategory" : "biriyani",
"mrp" : "38"
}
},
{
"_id" : ObjectId("58aadec0671a3794272f342f"),
"ShopId" : 435,
"products" : {
"productId" : "8234",
"productName" : "non veg",
"productCategory" : "biriyani",
"mrp" : "38"
}
}
]
Step 3) $group pipeline step to group the documents in the pipeline by the productCategory field from the denormalised documents and creates an array products that has fields from the previous pipeline. The $group pipeline operator is similar to the SQL's GROUP BY clause.
In SQL, you can't use GROUP BY unless you use any of the aggregation functions. The same way, you have to use an aggregation function called accumulator in MongoDB as well. You can read more about the aggregation functions here.
The accumulator operator you would need to create the array is $push.
In the same $group operation, the logic to calculate the count aggregate i.e. the number of documents in each category group is done using the $sum accumulator operator. The expression { $sum : 1 } returns the sum of values of the number of documents in each group.
To understand the pipeline, run the operation at this stage and analyse the results. So, executing the equivalent mongo operation
db.getCollection('shops').aggregate([
{ "$match": { "ShopId": 435 } }, // Step 1
{ "$unwind": "$products" }, // Step 2
{ // Step 3
"$group": {
"_id": "$products.productCategory",
"count": { "$sum": 1 },
"products": {
"$push": {
"productName": "$products.productName"
}
}
}
}
])
yields the following documents
[
{
"_id" : "meals",
"count" : 2,
"products" : [
{
"productName" : "non veg"
},
{
"productName" : "non veg"
}
]
},
{
"_id" : "juice",
"count" : 1,
"products" : [
{
"productName" : "apple"
}
]
},
{
"_id" : "biriyani",
"count" : 2,
"products" : [
{
"productName" : "non veg"
},
{
"productName" : "non veg"
}
]
}
]
Step 4) The last $group pipeline will then produce the desired result when you specify an _id value of null to calculate accumulated values for all the input documents above as a whole. The desired structure has a productsList array that can be created using the $push operator.
Again, running the final aggregate pipeline at this stage will give you the desired result, i.e. executing this in mongo shell
db.getCollection('shops').aggregate([
{ "$match": { "ShopId": 435 } }, // Step 1
{ "$unwind": "$products" }, // Step 2
{ // Step 3
"$group": {
"_id": "$products.productCategory",
"count": { "$sum": 1 },
"products": {
"$push": {
"productName": "$products.productName"
}
}
}
},
{ // Step 4
"$group": {
"_id": null,
"productList": {
"$push": {
"categoryname": "$_id",
"productcount": "$count",
"products": "$products"
}
}
}
}
])
will yield
{
"_id" : null,
"productList" : [
{
"categoryname" : "meals",
"productcount" : 2,
"products" : [
{
"productName" : "non veg"
},
{
"productName" : "non veg"
}
]
},
{
"categoryname" : "juice",
"productcount" : 1,
"products" : [
{
"productName" : "apple"
}
]
},
{
"categoryname" : "biriyani",
"productcount" : 2,
"products" : [
{
"productName" : "non veg"
},
{
"productName" : "non veg"
}
]
}
]
}
One thing to note here is when executing a pipeline, MongoDB pipes operators into each other. "Pipe" here takes the Linux meaning: the output of an operator becomes the input of the following operator. The result of each operator is a new collection of documents. So Mongo executes the above pipeline as follows:
collection | $match | $unwind | $group | $group => result

MongoDB match documents that contain an array field with ALL elements that match the query

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")
}
]
}
]
}

Resources