在 mongodb 中获取具有相同属性的文档
Get documents with same properties in mongodb
我有一个 collection 文件是这样的:
[
{
"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
});
});
这是一回事。你在这里 "aggregating" 什么都不是,只是将一份文件的内容与另一份文件进行比较。当然,您可以要求聚合框架执行类似 "filter" 的任何没有类似匹配的内容:
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 ] } }
}}
])
至少这样服务器处理才有意义。
但除此之外,一切都几乎相同,可能 "little" 客户端在此处计算 "intersection" 的开销更多。
我有一个 collection 文件是这样的:
[
{
"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
});
});
这是一回事。你在这里 "aggregating" 什么都不是,只是将一份文件的内容与另一份文件进行比较。当然,您可以要求聚合框架执行类似 "filter" 的任何没有类似匹配的内容:
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 ] } }
}}
])
至少这样服务器处理才有意义。
但除此之外,一切都几乎相同,可能 "little" 客户端在此处计算 "intersection" 的开销更多。