获取MongoDB文档中唯一嵌入/嵌套对象的列表

获取MongoDB文档中唯一嵌入/嵌套对象的列表,mongodb,Mongodb,考虑以下MongoDB“配方”集合: { "title" : "Macaroni and Cheese", "ingredients" : [ { "name" : "noodles", "qty" : "2 c" }, { "name" : "butter", "qty" : "2 tbl" }, { "name" : "cheese", "qty" : "1 c" }, ] }, { "title" : "Pound Cake", "ingredi

考虑以下MongoDB“配方”集合:

{
  "title" : "Macaroni and Cheese",
  "ingredients" : [
    { "name" : "noodles", "qty" : "2 c" },
    { "name" : "butter", "qty" : "2 tbl" },
    { "name" : "cheese", "qty" : "1 c" },
  ]
},
{
  "title" : "Pound Cake",
  "ingredients" : [
    { "name" : "sugar", "qty" : "1 lb" },
    { "name" : "butter", "qty" : "1 lb" },
    { "name" : "flour", "qty" : "1 lb" },
  ]
},
{
  "title" : "Dough",
  "ingredients" : [
    { "name" : "water", "qty" : "2 c" },
    { "name" : "butter", "qty" : "8 tbl" },
    { "name" : "flour", "qty" : "1 lb" },
  ]
}
我希望编写一个查询,生成一个“购物清单”,列出要购买的物品,以制作所有食谱。所以我基本上想把配料“面条”、“黄油”、“奶酪”、“糖”、“黄油”、“面粉”、“水”退回。我不要复制品。(例如,糖和黄油出现在多个食谱中,但我只想返回一次,即没有重复。)


是否可以在MongoDB中创建这样的查询?如果可以,该查询是什么?还是需要我为“配料”创建一个单独的集合?

在mongoshell中使用
foreach
操作符来实现这一点很有趣

var list = [];
db.recepies.find(
  {},
  {'ingredients.name' : 1, _id : 0}
).forEach(function(doc){
  var ingredients = doc.ingredients;
  for (var i=0; i< ingredients.length; i++){
    var ingredient = ingredients[i].name;
    if (list.indexOf(ingredient) == -1){
       list.push(ingredient)
    }
  }
});
var list=[];
db.recepies.find(
{},
{'components.name':1,_id:0}
).forEach(功能(文档){
var成分=文件成分;
对于(变量i=0;i

在此之后,
列表将包含所有元素。另外,我相信这在聚合框架中也是可行的。

以下查询将为您提供减去任何重复项的裸列表:

db.recipes.aggregate([{$unwind:"$ingredients"},{$group:{_id:"$ingredients.name"}}])

需要更多的工作来增加数量。如果单独指定数量单位,则更容易。

使用
distinct
查找
成分的不同值数组。name

db.recipes.distinct('ingredients.name')

产量
[“黄油”、“奶酪”、“面条”、“面粉”、“糖”、“水”]

这是您正在寻找的完整骨料管道:

db.recipes.aggregate([
       {$unwind:"$ingredients"},
       {$group:{_id:"$ingredients.name",
                quantity:{$first:"$ingredients.qty"},
                recipes:{$push:"$title"},
                total:{$sum:1}
               }
       },
       {$project:{_id:0,ingredient:"$_id", total:1, quantity:1, recipes:1}
])
这将展开数组,按成分分组,将它们相加以查看有多少配方需要它们,保持数量字段在您的用例中是相同的,并添加它所使用的配方列表。最后一步将grouped on字段重命名为“Component”

结果:

{ "quantity" : "1 lb", "recipes" : [  "Pound Cake",  "Dough" ], "total" : 2, "ingredient" : "flour" }
{ "quantity" : "2 c", "recipes" : [  "Dough" ], "total" : 1, "ingredient" : "water" }
{ "quantity" : "1 lb", "recipes" : [  "Pound Cake" ], "total" : 1, "ingredient" : "sugar" }
{ "quantity" : "1 c", "recipies" : [  "Macaroni and Cheese" ], "total" : 1, "ingredient" : "cheese" }
{ "quantity" : "2 tbl", "recipes" : [  "Macaroni and Cheese",  "Pound Cake",  "Dough" ], "total" : 3, "ingredient" : "butter" }
{ "quantity" : "2 c", "recipes" : [  "Macaroni and Cheese" ], "total" : 1, "ingredient" : "noodles" }

这是最好的解决方案-)我们如何在同一个查询中对结果集进行排序?您关心数量吗?不买这些东西没有多大意义——你需要买多少糖?好吧,这只是我实际问题的一个简单例子。在我的实际问题中,“配料”的每个实例实际上都有完全相同的字段值,即在所有“配方”中,“面粉”的“数量”始终为“1磅”,“黄油”的“数量”始终为“8磅”。我不关心你所说的数量的总和。但是,我也希望将“数量”字段与名称一起返回,这样我就有了“配料”的完整表示,例如{“名称”:“面粉”,“数量”:“1磅”}.db.recipes.distinct('components.name')是最好的解决方案我接受这个答案,因为它提供了我所需要的,但是,使用聚合也可以从“成分”(使用“$first”操作符)中包含更多字段,而不仅仅是名称。(如果我愿意的话,它甚至可以聚合“数量”字段。)因此,这个答案更强大,是帮助我解决问题的答案。c、 如果我只想返回“name”(如我的问题中所述),那么P.u1的答案就更简单了,因此我也对这个答案进行了投票。@All-我们如何使用Spring数据Mongo API实现它?