根据条件在 MongoDB 中投影

Projection in MongoDB based on Conditions

我在 c# 中的文档结构:

 public class HashTableDocument : Model
    {
        public int Id { get; set; }
        public Dictionary<string, HashSet<int>> items= new Dictionary<string, HashSet<int>>();
    }

在 Mongo:

{
    "_id" : 218,
    "items" : {
        "1" : [ 
            52711, 
            201610, 

        ],
        "2" : [ 
            246421, 
            390200
        ],
        "3" : [ 
            105628, 
            768519
        ],
        "26" : [ 
            17435, 
            22252, 
            61389, 
            65184, 
            72859, 
            81421, 
            931469, 
            933505, 
            938377, 
            959836
        ],
        "27" : [ 
            26917, 
            38706, 
            53862, 
            111816, 
            827294, 
            858348, 
            870334
        ]
    }
}

我希望能够将任何整数列表 ('x') 传递给 Mongo。如果值包含给定列表 ('x') 中的任何整数,则仅投影那些键值对。

例如,在上面的文档中。如果我将 List = { 52711, 105628, 17435, 81421} 传递给 Mongo 那么 应该 return

{
    "_id" : 218,
    "items" : {
        "1" : [ 
            52711, 
            201610, 

        ],
        "3" : [ 
            105628, 
            768519
        ],
        "26" : [ 
            17435, 
            22252, 
            61389, 
            65184, 
            72859, 
            81421, 
            931469, 
            933505, 
            938377, 
            959836
        ],
     }
}

因为每个键的值在其列表中都包含 至少一个元素

我不知道 C# 语法,但这里介绍了如何使用聚合框架来实现。请注意,这使用了 3.4.4 版本中引入的 $objectToArray 表达式。

> db.test.aggregate([{
  $project: {
    x: {
      $filter: {
        input: {$objectToArray: "$items"},
        cond: {
          $gt: [
            {
              $size: {
                $filter: {
                  input: "$$this.v",
                  as: "int",
                  cond: {$in: ["$$int", [52711, 105628, 17435, 81421]]}
                }
              }
            },
            0
          ]
        }
      }
    }
  }
}])
{
  "result": [
    {
      "_id": 218,
      "items": [
        {
          "k": "1",
          "v": [
            52711,
            201610
          ]
        },
        {
          "k": "3",
          "v": [
            105628,
            768519
          ]
        },
        {
          "k": "26",
          "v": [
            17435,
            22252,
            61389,
            65184,
            72859,
            81421,
            931469,
            933505,
            938377,
            959836
          ]
        }
      ]
    }
  ],
  "ok": 1
}

但是,当您拥有像您这样的结构时,进行此类计算通常并不容易。此聚合不能使用任何索引来限制其搜索。您是否考虑过改用以下架构?

{
  "_id": 218,
  "items": [
    {k: "1", v: [52711, 201610]},
    {k: "2", v: [246421, 390200]},
    {k: "3", v: [105628, 768519]},
    {k: "26", v: [17435, 22252, 61389, 65184, 72859, 81421, 931469, 933505, 938377, 959836]},
    {k: "27", v: [26917, 38706, 53862, 111816, 827294, 858348, 870334]},
  ]
}

那么你的问题就变得简单多了,你可以改为:

db.test.aggregate([
  {$match: {"items.v": {$in: [52711, 105628, 17435, 81421]}}},
  {
    $project: {
      items: {
        $filter: {
          input: "$items",
          cond: {
            $size: {
              $setIntersection:
                  [[52711, 105628, 17435, 81421], "$$this.v"]
            }
          }
        }
      }
    }
  }
])

并且如果您在字段 "items.v" 上创建了索引,初始 $match 阶段可以利用该索引来执行更高效的查询。