1

我有一个数据集,看起来是这样的:麻烦MongoDB中创建的查询与子查询

{ 
 
    "id": "02741544", 
 
    "items": [{ 
 
    "item": "A" 
 
    }] 
 
}, { 
 
    "id": "02472691", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }, { 
 
    "item": "C" 
 
    }] 
 
}, { 
 

 
    "id": "01316523", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }] 
 
}, { 
 
    "id": "01316526", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "B" 
 
    }] 
 
}, { 
 
    "id": "01316529", 
 
    "items": [{ 
 
    "item": "A" 
 
    }, { 
 
    "item": "D" 
 
    }] 
 
},

我想制作一个查询,这将使我的输出,看起来像这样的:

{ 
 
    "item": "A", 
 
    "ids": [{ 
 
    "id": "02741544" 
 

 
    }, { 
 
    "id": "02472691" 
 

 
    }, { 
 
    "id": "01316523" 
 

 
    }, { 
 
    "id": "01316526" 
 

 
    }, { 
 
    "id": "01316529" 
 

 
    }] 
 
}, { 
 
    "item": "B", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }, { 
 
    "id": "01316523" 
 

 
    }, { 
 
    "id": "01316526" 
 

 
    }] 
 
}, { 
 
    "item": "C", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }] 
 
}, { 
 
    "item": "D", 
 
    "ids": [{ 
 
    "id": "02472691" 
 

 
    }] 
 
},

基本上,我试图从对象中的项目数组中获取不同的项目,然后为每个在其项目数组中具有该项目的obj返回一个id数组。

回答

2

更好地利用aggregation framework中,你需要运行一个由以下管道的步骤(给定的顺序)操作:

  1. $unwind - 这第一步将压平items阵列即它为每个数组条目生成每个文档的副本。这对于将流水线下方的文档处理为“非规范化”文档是必要的,您可以将这些文档聚合为组。
  2. $group - 这组扁平文件由item子文档密钥,使用该$push蓄电池运营商创建ids列表。

- 更新 -

由于@AminJ在评论中指出,如果items可以有重复的项目值,你不想在结果中重复的ID,你可以使用$addToSet代替$push

下面的例子说明这一点:

db.collection.aggregate([ 
    { "$unwind": "$items" }, 
    { 
     "$group": { 
      "_id": "$items.item", 
      "ids": { 
       "$push": { "id": "$id" } /* or use 
       "$addToSet": { "id": "$id" } if you don't want duplicate ids */      
      } 
     } 
    } 
]) 

样本输出

{ 
    "_id" : "A", 
    "ids" : [ 
     { "id" : "02741544" }, 
     { "id" : "02472691" }, 
     { "id" : "01316523" }, 
     { "id" : "01316526" }, 
     { "id" : "01316529" } 
    ] 
} 

/* 2 */ 
{ 
    "_id" : "B", 
    "ids" : [ 
     { "id" : "02472691" }, 
     { "id" : "01316523" }, 
     { "id" : "01316526" } 
    ] 
} 

/* 3 */ 
{ 
    "_id" : "C", 
    "ids" : [ 
     { "id" : "02472691" } 
    ] 
} 

/* 4 */ 
{ 
    "_id" : "D", 
    "ids" : [ 
     { "id" : "01316529" } 
    ] 
} 

aggregate()功能的结果是一个光标移动到由聚合流水线操作的最后阶段中产生的文档。所以如果你想在一个数组中得到结果,你可以使用光标的方法,该方法返回一个数组,该数组包含来自它的所有文档。

例如:

var pipeline = [  
     { "$unwind": "$items" }, 
     { 
      "$group": { 
       "_id": "$items.item", 
       "ids": { 
        "$push": { "id": "$id" } /* or use 
        "$addToSet": { "id": "$id" } if you don't want duplicate ids */      
       } 
      } 
     } 
    ], 
    results = db.collection.aggregate(pipeline).toArray(); 

printjson(results); 
+1

这可能是值得一提,如果'items'可以有重复的'item'值,并且你不想在结果中可以使用'addToSet'而不是'push'。 –

+0

@AminJ好点 – chridam

+0

只要内容进行,它就会给出所需的输出,但不会将结果作为一组对象返回。这是如何完成的? – TWLATL

0

下面是一个使用聚合管道解决方案:

db.col.aggregate([ 
     { 
      $unwind: "$items" 
     }, 
     { 
      $project: { 
       id: 1, 
       item: "$items.item" 
      } 
     }, 
     { 
      $group: { 
       _id: "$item", 
       ids: { 
        $push: "$id" 
       } 
      } 
     } 
    ])