基于条件的MongoDB投影

时间:2017-04-19 20:18:04

标签: c# mongodb mongodb-query aggregation-framework projection

我在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
        ]
    }
}

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

例如,在上面的文件中。如果我然后将List = { 52711, 105628, 17435, 81421}传递给Mongo 它应该返回

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

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

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

1 个答案:

答案 0 :(得分:2)

我不知道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"]
            }
          }
        }
      }
    }
  }
])

如果您在字段&#34; items.v&#34;上创建了索引,则初始$match阶段可以利用该索引进行更有效的查询。