过滤器阵列子文档,同时还返回父数据,如果空 [英] Filter subdocument array while still returning parent data if empty

查看:142
本文介绍了过滤器阵列子文档,同时还返回父数据,如果空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的方法从这个问题<一href=\"http://stackoverflow.com/questions/15117030/how-to-filter-array-in-subdocument-with-mongodb\">How在MongoDB中子文档过滤​​阵列

它将按预期除非没有数组中的元素的测试赛。在这种情况下,我只是得到一个没有父数据空数组。

样本数据

  {
  _id:53712c7238b8d900008ef71c,
  dealerName:TestDealer,
  电子邮件:test@test.com
  地址: {..},
  库存:[
      {
          头衔:主动,
          汽车: [
            {
              _id:53712fa138b8d900008ef720,
              createdAt:2014-05-12T20:08:00.000Z,
              标签:
                 车辆
               ]
               OPTS:{...},
               上市:假的,
               披露:{...},
               细节:{...}
           },
           {
              _id:53712fa138b8d900008ef720,
              createdAt:2014-05-12T20:08:00.000Z,
              标签:[...]
              OPTS:{...},
              上市:真实,
              披露:{...},
              细节:{...}
            }
         ]
     },
     {
         头衔:卖,
         汽车: []
     }
  ]
}

试图做

在我的查询,我想回报用户(文件)顶级信息(dealerName,电子邮件),并包含所有的车辆在活动库存有上市的属性设置为<$ C的属性叫车$ C>真正。

如何FAR I GOT

这是我的查询。 (我用猫鼬,但大多使用本地蒙戈功能)

  {
        $比赛:
          电子邮件:params.username
      }
      {
        $放松:'$库存
      }
      {
        $比赛:
          inventories.title:主动
      }
      {
        $开卷:
          '$ inventories.vehicles
      }
      {
        $比赛:
          inventories.vehicles.listed:
            $ EQ:真
      }
      {
        $组:
          _id:'$ _id
          dealerName:
            $第一:'$ dealerName
          电子邮件:
            $第一:'$电子邮件
          地址:
            $第一:'$地址'
          汽车:
            $推:'$ inventories.vehicles
      }

问题

起初,我还以为我的查​​询是很好,但是,如果没有车辆被标记为,查询只返回一个空数组。这是有道理的,因为

  {
        $比赛:
          inventories.vehicles.listed:
            $ EQ:真
      }

不匹配任何东西,但我仍想获得dealerName以及他的电子邮件

所需的输出,如果没有车辆MATCH

  [{dealerName:TestDealer,电子邮件:test@test.com车辆:[]}]

实际输出

  []


解决方案

您可以用$纂而不是$匹配在这种情况下,像这样

  db.collectionName.aggregate({
  $纂:{
    $ COND:{
       如果:{$和:[{$不是:$ dealerName},{$不会:$标题},{$ EQ:[$列出的假]},
       然后:$$剪枝,
       其他:$$下潜
    }
  }
})

我们需要第一个条件跳过顶层文件,第二个条件跳过第二级和第三个修剪车辆。 否$开卷需要在这种情况下!

一件事:$仅在2.6纂可用

I am using the method from this question How to filter array in subdocument with MongoDB

It works as expected except when none of the elements in the array match the test. In that case, I just get an empty array with no parent data.

SAMPLE DATA

 {
  "_id": "53712c7238b8d900008ef71c",
  "dealerName": "TestDealer",
  "email": "test@test.com",
  "address": {..},
  "inventories": [
      {
          "title": "active",
          "vehicles": [
            {
              "_id": "53712fa138b8d900008ef720",
              "createdAt": "2014-05-12T20:08:00.000Z",
              "tags": [
                 "vehicle"
               ],
               "opts": {...},
               "listed": false,
               "disclosures": {...},
               "details": {...}
           },
           {
              "_id": "53712fa138b8d900008ef720",
              "createdAt": "2014-05-12T20:08:00.000Z",
              "tags": [...],
              "opts": {...},
              "listed": true,
              "disclosures": {...},
              "details": {...}
            }
         ]
     },
     {
         "title": "sold",
         "vehicles": []
     }
  ]
}

TRYING TO DO

In my query I would like to return the user (document) top-level info (dealerName, email) and a property called vehicles containing all the vehicles in the "active" inventory that have the property listed set to true.

HOW FAR I GOT

This is my query. (I use Mongoose but use mostly native Mongo features)

      {
        $match:
          email: params.username
      }
      {
        $unwind: '$inventories'
      }
      {
        $match:
          'inventories.title': 'active'
      }
      {
        $unwind:
          '$inventories.vehicles'
      }
      {
        $match:
          'inventories.vehicles.listed':
            $eq: true
      }
      {
        $group:
          _id: '$_id'
          dealerName:
            $first: '$dealerName'
          email:
            $first: '$email'
          address:
            $first: '$address'
          vehicles:
            $push: '$inventories.vehicles'
      }

THE PROBLEM

At first, I thought my query was fine, however, if none of the vehicles are marked as listed, the query just returns an empty array. This makes sense since

      {
        $match:
          'inventories.vehicles.listed':
            $eq: true
      }

Doesn't match anything but I would still like to get the dealerName as well as his email

DESIRED OUTPUT IF NO VEHICLES MATCH

[{"dealerName": "TestDealer", "email": "test@test.com", vehicles : []}]

ACTUAL OUTPUT

[]

解决方案

You could use $redact instead of $match in this case, like this

db.collectionName.aggregate({
  $redact:{
    $cond:{ 
       if:{$and:[{$not:"$dealerName"},{$not:"$title"},{$eq:["$listed",false]}, 
       then: "$$PRUNE", 
       else: "$$DESCEND" 
    }
  }
})

We need first condition to skip top level documents, second condition to skip second level and third one to prune vehicles. No $unwind needed in this case!

One more thing: $redact available only in 2.6

这篇关于过滤器阵列子文档,同时还返回父数据,如果空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆