MongoDB将包含数组字段的文档与所有匹配查询的元素进行匹配

$elementMatch的MongoDB文档:

$ elemMatch操作符将包含数组字段的文档与至less一个匹配所有指定查询条件的元素进行匹配。

但是,如何将包含数组字段的文档与匹配查询的所有元素进行匹配?

例如,我有这样的文件:

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

我需要匹配所有formats.prices.price > 5的所有文档

如果我使用以下查询:

 { 'formats.prices': { $elemMatch: { price: { $gte: 5 } } } } 

该文件将被匹配,因为至less有一个价格> 5

我也试过这个,但似乎并不奏效:

 { 'formats.prices': { $all: { $elemMatch: {price: { $gte: 0.98 } } } } } 

有没有一种方法可以排除那些至less看不到一个价格的文件?

find了! 这很容易,只需使用$not操作符并检查相反的(<5):

 { 'formats.prices': { $not: { $elemMatch: {price: { $lt: 5 } } } } } 

您可以使用Aggegation或MAP REDUCE来实现它:

第一个解决scheme是使用Map-Reduce

我创build了一个名为“格式”的集合,并插入以下数据:

 { "_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 } } ) 

输出:

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

使用聚合的第二个解决scheme

使用集合运算符$ unwind和$ size,我们可以使用下面的查询得到所需的结果:

在“Formats”和“Formats.prices”的$ unwind之后,获取“Formats.prices”的大小,然后在“prices”上执行$匹配 ,并再次计算“Formats.prices”的新大小。

如果大小相同,则“格式”字段中的所有“价格”都大于5,文档将被投影。

 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() 

输出:

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