【问题标题】:Filter multiple arrays with $redact使用 $redact 过滤多个数组
【发布时间】:2016-03-17 18:34:09
【问题描述】:

我实际上是在尝试发出一个 mongodb 请求,该请求首先在一个列表中填充过滤器,然后在另一个列表中。

说明

我的数据库中有以下对象:

{
  "_id": ObjectId("..."),
  "title": "MySuperProject",
  "files": [
    {
      "title":"My skiing day !",
      "right":[{
        "role":"USER",
        "access":["read"]
      }]
    },
    {
      "title":"My little dog, so cute !",
      "right":[{
        "role":"OTHER",
        "access":["read"]
      }]
    }
  ],

"people": [
    {
      "userName":"borat",
      "role":"OTHERONE",
      "right":[{
        "role":"USER",
        "access":["read"]
      }]
    },
    {
      "userName":"Thomas",
      "role":"OTHER",
      "right":[{
        "role":"OTHER",
        "access":["read"]
      }]
    }
  ]
}

我需要什么

我需要将一个参数传递给我的函数,即当前用户角色。就我而言,我传递了“USER”角色。

这样,我需要检索这个结果:

{
  "_id": ObjectId("..."),
  "title": "MySuperProject",
  "files": [
    {
      "title":"My skiing day !",
      "right":[{
        "role":"USER",
        "access":["read"]
      }]
    }
  ],

"people": [
    {
      "userName":"borat",
      "role":"OTHER",
      "right":[{
        "role":"USER",
        "access":["read"]
      }]
    }
  ]
}

这减少了与我匹配的项目角色上的两个列表。

我有什么

我有一个通过“角色”属性减少文件列表的查询。

事实上,在我的人员列表中,我有两次角色属性:

  • 一次性确定人员角色
  • 一次性确定哪些人可以访问(正确访问)人员资料

我的查询通过匹配遇到的第一个角色(people.role 而不是 people.right.role)来减少人员结果集。

我的查询如下:

db.t.aggregate([
  {
    $match: {
      "title": projectTitle
    }
  },
  {
    $redact: {
      $cond: [{
        $eq: [role, {
          $ifNull: ["$role", role]
        }]
      }, "$$DESCEND", "$$PRUNE"]
    }
  },
  {
    $redact: {
      $cond: [{
        $gt: [{
          $size: {
            $ifNull: ["$right", [1]]
          }
        }, 0]
      }, "$$DESCEND", "$$PRUNE"]
    }
  },
])

总结:我需要查询减少人员和匹配两个 right.role 值的文件列表

【问题讨论】:

    标签: node.js mongodb mongodb-query aggregation-framework


    【解决方案1】:

    $redact 管道阶段不是最好的工具,因为它不能很好地转化为“不同级别的不同条件”,也不能很好地转化为 “以不同方式处理不同的数组” 根据其预期功能的性质。

    这里更好的情况是普通的旧数组过滤,已经有一段时间了。

    如果你有,最好的选择是来自 MongoDB 3.2 的 $filter

    db.t.aggregate([
        { "$project": {
            "title": 1,
            "files": {
                "$filter": {
                    "input": "$files",
                    "as": "file",
                    "cond": { "$eq": [ "$$file.right.role", "USER" ] }
                }
            },
            "people": {
                "$filter": {
                    "input": "$people",
                    "as": "person",
                    "cond": { "$eq": [ "$$person.right.role", "USER" ] }
                }
            }
        }}
    ])
    

    对于 MongoDB 2.6,如果您的数组元素是真正“不同的”并且在一个文档中没有两个相同,那么您可以使用 $map$setDifference “模拟”该较新的函数以删除任何 false数组的结果:

    db.t.aggregate([
        { "$project": {
            "title": 1,
            "files": {
                "$setDifference": [
                    { "$map": {
                        "input": "$files",
                        "as": "file",
                        "in": {
                           "$cond": [
                               { "$eq": [ "$$file.right.role", "USER" ] },
                               "$$file",
                               false
                           ]
                        }
                    }},
                    [false]
                ]
            },
            "people": {
                "$setDifference": [
                    { "$map": {
                        "input": "$people",
                        "as": "person",
                        "in": {
                           "$cond": [
                               { "$eq": [ "$$person.right.role", "USER" ] },
                               "$$person",
                               false
                           ]
                        }
                    }},
                    [false]
                ]
            }
        }}
    ])
    

    这是相同的基本条件测试,除了在后一种情况下$map 只返回作为输入提供的每个数组元素的元素。所以匹配的元素或false 的值,然后将通过“设置比较”从$setDifferencefalse 删除。

    这些都是单流水线阶段操作,因此它们是最快的方法。

    与往常一样,除非您确实需要将这些信息传递到进一步的聚合管道阶段,或者如果您确实将数组中的内容减少了“显着”数量,从而为您节省大量网络流量,那么它总是会更好在客户端对数据库本身进行这种“过滤”。

    这些进程都不会真正有太多开销,但客户端代码可以说是一样简单的,并且可能从“一点”更少的网络流量中获得的东西可能会丢失在服务器上的处理成本中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 2017-08-30
      • 1970-01-01
      相关资源
      最近更新 更多