有一个看起来像这样的项目( 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时我完全迷路了,我不确定这是否是最好的方法...

最佳答案

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

  • $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以避免重复使用过滤器值。 IE。
    'description.lang':'ca','shortDescription.lang':'ca','variants.attrs.displayName.lang':'ca'

    10-06 14:19