【问题标题】:Get documents with same properties in mongodb在mongodb中获取具有相同属性的文档
【发布时间】:2015-07-05 13:55:11
【问题描述】:

我有一个包含这样的文档的集合:

[
  {
    "user_id": 1,
    "prefs": [
      "item1",
      "item2",
      "item3",
      "item4"
    ]
  },
  {
    "user_id": 2,
    "prefs": [
      "item2",
      "item5",
      "item3"
    ]
  },
  {
    "user_id": 3,
    "prefs": [
      "item4",
      "item3",
      "item7"
    ]
  }
]

我想要编写一个聚合,它将获得一个 user_id 并生成一个列表,其中包含映射到列表中相同 prefs 数量的所有用户。例如,如果我为 user_id = 1 运行聚合,我必须得到:

[
  {
    "user_id": 2,
    "same": 1
  },
  {
    "user_id": 3,
    "same": 2
  }
]

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    您不能在此处使用像 "user_id": 1 这样简单的输入在此处编写任何查询,但您可以检索该用户的文档,然后将该数据与您正在检索的其他文档进行比较:

    var doc = db.collection.findOne({ "user_id": 1 });
    
    db.collection.aggregate([
       { "$match": { "user_id": { "$ne": 1 } } },
       { "$project": {
           "_id": 0,
           "user_id": 1
           "same": { "$size": { "$setIntersection": [ "$prefs", doc.prefs ] } }             
       }}
    ])
    

    这是一种方法,但与比较客户端中的每个文档也没有太大区别:

    function intersect(a,b) {
        var t;
        if (b.length > a.length) t = b, b = a, a = t;
        return a.filter(function(e) {
            if (b.indexOf(e) != -1) return true;
        });
    }
    
    var doc = db.collection.findOne({ "user_id": 1 });
    
    db.collection.find({ "user_id": { "$ne": 1 } }).forEach(function(mydoc) {
        printjson({ 
            "user_id": mydoc.user_id, 
            "same": intersect(mydoc.prefs, doc.prefs).length
        });
    });
    

    这是同样的事情。您在这里并没有真正“聚合”任何内容,而只是将一个文档内容与另一个文档内容进行比较。当然,您可以要求聚合框架执行诸如“过滤”掉任何没有类似匹配项的操作:

    var doc = db.collection.findOne({ "user_id": 1 });
    
    db.collection.aggregate([
       { "$match": { "user_id": { "$ne": 1 } } },
       { "$project": {
           "_id": 0,
           "user_id": 1
           "same": { "$size": { "$setIntersection": [ "$prefs", doc.prefs ] } }             
       }},
       { "$match": { "same": { "$gt": 0 } }}
    ])
    

    虽然实际上在进行投影之前删除任何计数为零的文档会更有效:

    var doc = db.collection.findOne({ "user_id": 1 });
    
    db.collection.aggregate([
       { "$match": { "user_id": { "$ne": 1 } } },
       { "$redact": {
           "$cond": {
               "if": { "$gt": [
                   { "$size": { "$setIntersection": [ "$prefs", doc.prefs ] } },
                   0
               ]},
               "then": "$$KEEP",
               "else": "$$PRUNE"
           }
       }},
       { "$project": {
           "_id": 0,
           "user_id": 1
           "same": { "$size": { "$setIntersection": [ "$prefs", doc.prefs ] } }             
       }}
    ])
    

    至少那样做服务器处理是有意义的。

    但除此之外,一切都差不多,在客户端计算此处的“交叉点”时可能会增加“一点”开销。

    【讨论】:

      猜你喜欢
      • 2021-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-24
      相关资源
      最近更新 更多