根据条件在 MongoDB 中投影
Projection in MongoDB based on Conditions
我在 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
]
}
}
我希望能够将任何整数列表 ('x') 传递给 Mongo。如果值包含给定列表 ('x') 中的任何整数,则仅投影那些键值对。
例如,在上面的文档中。如果我将 List = { 52711, 105628, 17435, 81421}
传递给 Mongo 那么
应该 return
{
"_id" : 218,
"items" : {
"1" : [
52711,
201610,
],
"3" : [
105628,
768519
],
"26" : [
17435,
22252,
61389,
65184,
72859,
81421,
931469,
933505,
938377,
959836
],
}
}
因为每个键的值在其列表中都包含 至少一个元素。
我不知道 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"]
}
}
}
}
}
}
])
并且如果您在字段 "items.v" 上创建了索引,初始 $match
阶段可以利用该索引来执行更高效的查询。
我在 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
]
}
}
我希望能够将任何整数列表 ('x') 传递给 Mongo。如果值包含给定列表 ('x') 中的任何整数,则仅投影那些键值对。
例如,在上面的文档中。如果我将 List = { 52711, 105628, 17435, 81421}
传递给 Mongo 那么
应该 return
{
"_id" : 218,
"items" : {
"1" : [
52711,
201610,
],
"3" : [
105628,
768519
],
"26" : [
17435,
22252,
61389,
65184,
72859,
81421,
931469,
933505,
938377,
959836
],
}
}
因为每个键的值在其列表中都包含 至少一个元素。
我不知道 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"]
}
}
}
}
}
}
])
并且如果您在字段 "items.v" 上创建了索引,初始 $match
阶段可以利用该索引来执行更高效的查询。