在mongodb中获取具有相同属性的文档(Get documents with same properties in mongodb)

编程入门 行业动态 更新时间:2024-10-26 18:21:02
在mongodb中获取具有相同属性的文档(Get documents with same properties in mongodb)

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

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

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

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

I have a collection with documents like this:

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

What I want is to write an aggregation which will get a user_id and producer a list containing all users mapped to the number of same prefs in their lists. for example if I run the aggregation for user_id = 1, I have to get:

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

至少那样做服务器处理会有一些意义。

但除此之外,它们几乎都是一样的,在客户端处理“交叉点”时可能会产生“少量”开销。

You cannot write any query here with input as simple as "user_id": 1 here, but you can retrieve the document for that user and then get a comparison of that data to the other documents you are retrieving:

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 ] } }             
   }}
])
 

Which is one approach, but also not that much different to comparing each document in the client:

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
    });
});
 

It's the same thing. You are not really "aggregating" anything here but just making comparisons of one documents content against the other. Of course you can ask the aggregation framework to do something like "filter" out anything that does not have a similar match:

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 } }}
])
 

Though actually that would be more efficient to remove any documents with a zero count before doing the projection:

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 ] } }             
   }}
])
 

And at least then that would make some sense to do the server processing.

But otherwise, it's all pretty much the same, with possibly a "little" more overhead on the client working out the "intersection" here.

更多推荐

本文发布于:2023-08-07 16:15:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1465503.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:属性   文档   mongodb   documents   properties

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!