mongodb - 在mongodb中获取具有相同属性的文档

标签 mongodb mongodb-query aggregation-framework

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

[
  {
    "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
  }
]

最佳答案

您不能在此处使用像 "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 ] } }             
   }}
])

至少这样服务器处理才有意义。

但除此之外,一切都几乎相同,只是客户端在此处计算“交叉点”时可能会多“一点”开销。

关于mongodb - 在mongodb中获取具有相同属性的文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31098064/

相关文章:

mongodb是否有可能获取集合中文档中对象的所有键和值?

MongoDB 过滤器(如果所有键都作为字段存在)

node.js - 如何在 MongoDB 中通过单个查询获取计数和最大日期?

node.js - 在 mongodb 数组中查找嵌套字段

MongoDB 只比较日期而不比较时间

node.js - MongoDB closeSphere 只返回 100 个结果?

mongodb - GridFS 使用文件名作为索引

mongodb - 使用 $near 按存储在文档中的距离过滤文档

mongodb 引用查询

node.js - 如何将这两个单独的聚合查询合并为一个查询?