匹配数组的一个字段时返回整个文档

时间:2014-04-30 12:46:22

标签: mongodb aggregation-framework

我有一个像这样的集合:

db.collection1 = 
{
    "_id" : ObjectId(),
    "array" : [
        {
            "userid" : ObjectId(),
            "subfield1" : string,
            "subfield2" : number,
            "subfield3" : number,
            "subfield4" : Date
        },...
    ],
    "field1" : date,
    "field2" : date,
    "field3" : date,
    "field4" : date,
    "field5" : number,
    "field6" : [],
    "field7" : String,
    "field8" : {}
},...

现在,我根据数组中的userid字段使用查找查询,有点像这样:

db.collection1.find({array:{"$elemMatch":{userid:uId}})

但我还想要的是在检索记录之前它应该获取该特定数组元素并将其作为返回对象的属性追加。

我的第二个问题是:

db.collection1.find({'array.userId':uId},{'array.$':1})

但是我希望将第二个查询的结果作为第一个查询中返回的对象的附件进行追加

我希望我很清楚......

我的预测是这样的:

{array.subfield2:0,array.subfield3:0,field2:0,field6:0,field7:0}

所以这就是我想要的结果......支持有3个用户,第三个用户匹配我传递的userId。检索到的文档应如下所示。

{
 _id: ObjectId(),
 array:[
 {
  userid:ObjectId(1),
  subfield1:string,
  subfield4:Date
 },
 {
  userid:ObjectId(2),
  subfield1:string,
  subfield4:Date
 },
 {
  userid:ObjectId(3),
  subfield1:string,
  subfield4:Date
 }],
 "field1" : date,
 "field3" : date,
 "field4" : date,
 "field5" : number,
 "field8" : {},
 DynamicField://This is the userobj of the 3rd usr which matches. Whole & intact 
 {
   "userid" : ObjectId(3),
   "subfield1" : string,
   "subfield2" : number,
   "subfield3" : number,
   "subfield4" : Date
 }
}

1 个答案:

答案 0 :(得分:0)

我认为很多人都被你的“附加”术语搞糊涂了,但是如果我在你所说的内容之间读到你似乎想要返回“整个文件”但只包括“匹配”元素“的数组。

与所有常规“字段选择”技术一样,您必须对MongoDB非常具体,并在投影中包含所有字段名称:

db.collection1.find(
    { "array.userid": uId },   // Don't need elemMatch with one field
    {
        "array.$": 1,
        "field1": 1,
        "field2": 1,
        "field3": 1,
        "field4": 1,
        "field5": 1,
        "field6": 1,
        "field7": 1,
        "field8": 1,
    }
)

_id总是包含在内,除非明确排除,否则您不能在此处“混合”其他包含/排除,而不是因为您需要数组中的匹配位置而有意义。

编辑:我不知道您为什么要这样做,对我来说上面的表格要好得多:

 db.collection1.aggregate([
     // Filter the matching document, as you do not want to do the rest of the
     // steps over the whole collection
     { "$match": {
         "array.userid": uId,   // Don't need elemMatch with one field
     }},

     // Store the original document, and a copy of the array
     { "$project": {
         "array": 1,
         "field1": 1,
         "field3": 1,
         "field4": 1,
         "field5": 1,
         "field8": 1,
         "dynamicField": "$array"
     }},

     // Unwind the array
     { "$unwind": "$dynamicField" },

     // Just match the field you want
     { "$match": { "dynamicField.userid": uId } },

     // Play with the other array now
     { "$unwind": "$array" },

     // Change the projection
     { "$project": {
         "array.userId": "$array.userId",
         "array.subfield1": "$array.subfield1", 
         "array.subfield4": "$array.subfield4", 
         "field1": 1,
         "field2": 1,
         "field3": 1,
         "field4": 1,
         "field5": 1,
         "field6": 1,
         "field7": 1,
         "field8": 1,
         "dynamicField": 1
     }},

     // Group back the array
     { "$group": {
         "_id": "$_id",
         "array": { "$push": "$array" },
         "field1": { "$first": "$field1" },
         "field3": { "$first": "$field3" },
         "field4": { "$first": "$field4" },
         "field5": { "$first": "$field5" },
         "field8": { "$first": "$field8" },
         "dynamicField": { "$first": "$dynamicField" }
     }}

 ])