Mongodb $ project:$ filter子数组

时间:2016-09-06 19:39:36

标签: mongodb mongodb-query

有一个项目(mongoose)架构看起来像这样(简化为问题的重要性):

{
    brand: {
        name: String,
    },
    title: String,
    description: [{ lang: String, text: String }],
    shortDescription: [{ lang: String, text: String }],
    variants: {
        cnt: Number,
        attrs: [
            {
                displayType: String,
                displayContent: String,
                displayName: [{ lang: String, text: String }],
                name: String,
            },
        ],
    }
}

我正在尝试按语言过滤项目,因此我构建了以下查询:

db.items.aggregate([
    { $match: { 'description.lang': 'ca', 'shortDescription.lang': 'ca' } },
    { $project: {
        'brand.name': 1,
        title: 1,
        description: {
            '$filter': {
                input: '$description',
                as: 'description',
                cond: { $eq: ['$$description.lang', 'ca'] }
            }
        },
        shortDescription: {
            '$filter': {
                input: '$shortDescription',
                as: 'shortDescription',
                cond: { $eq: ['$$shortDescription.lang', 'ca'] }
            }
        },
        'variants.cnt': 1,
        'variants.attrs': 1
    } }
])

它按预期工作:按语言过滤descriptionshortDescription。现在我想知道是否有可能过滤每个variants.attrs.$.displayName。有没有办法做到这一点?

我一直在尝试$unwind variant.attrs但是当我再次尝试$group时我完全迷失了,我不确定这是否是最好的方式... < / p>

1 个答案:

答案 0 :(得分:8)

你快到了。请尝试以下步骤:

  • $unwind阶段之前使用$project阶段展开外部文档数组,即variants.attrs
  • variants.attrs.displayName阶段为子数组$project添加过滤器。
  • 您必须投影variants密钥的所有子字段。
  • 接下来,除了子数组之外的所有元素都添加$group阶段和分组。使用$push逐级重建子数组。
  • 最后,添加$project阶段以将文档重建为其原始结构。

    db.items.aggregate([
      { $match: { 'description.lang': 'ca', 'shortDescription.lang': 'ca' } },
      { $unwind : "$variants.attrs" },
      { $project: {
         '_id' : 1,
         'brand.name': 1,
         title: 1,
         description: {
            '$filter': {
                input: '$description',
                as: 'description',
                cond: { $eq: ['$$description.lang', 'ca'] }
            }
         },
         shortDescription: {
           '$filter': {
               input: '$shortDescription',
               as: 'shortDescription',
               cond: { $eq: ['$$shortDescription.lang', 'ca'] }
            }
         },
         'variants.attrs.displayName' : {
            '$filter' : {
               input: '$variants.attrs.displayName',
               as: 'variants_attrs_displayName',
               cond: { $eq : ['$$variants_attrs_displayName.lang','ca']}
            }
          },
    
          'variants.cnt': 1,
          'variants.attrs.displayType': 1,
          'variants.attrs.displayContent' : 1,
          'variants.attrs.name' : 1
        } 
     } , { $group:
              {
                _id : { 
                    _id: "$_id",
                    title: "$title",
                    brand:"$brand",
                    description:"$description",
                    shortDescription:"$shortDescription", 
                    variants_cnt : "$variants.cnt"
                    },
                variants_attrs : { $push : 
                { 
                  displayType : "$variants.attrs.displayType",
                  displayContent : "$variants.attrs.displayContent",
                  displayName : "$variants.attrs.displayName",
                  name: "$variants.attrs.name" 
                }
              }
            }
        },
    { $project : 
     {
        "_id" : 0,
        brand : "$_id.brand",
        title : "$_id.title",
        description : "$_id.description",
        shortDescription : "$_id.shortDescription",
        variants : {
          cnt : "$_id.variants_cnt" ,
          attrs : "$variants_attrs"
         }
       }  
     }
    ])
    

根据您的使用情况,您应重新考虑data model design以避免重复使用过滤器值。即 &#39; description.lang&#39;:&#39; ca&#39;,&#39; shortDescription.lang&#39;:&#39; ca&#39;,&#39; variants.attrs.displayName。 lang&#39;:&#39; ca&#39;