我已经挣扎了一段时间,所以切入追逐:
我在数据库中有这个对象
{
topic: [
{
topicName: "Reproduction in plants",
subTopic: ["Pollination", "Other Topic"]
},
{
topicName: "Plant Cycle",
subTopic: ["Pollination", "Photosynthesis"]
},
]
}
我在这里要解决的问题是如何进行满足以下条件的查询:
所以,让我说我想从查询中得到这个:
在我目前的解决方案中:
filterQueries['topic.topicName'] = { $in: ["Reproduction in plants", "Plant Cycle"] };
filterQueries['topic.subTopic'] = { $in: ["Photosynthesis", "Pollination"] };
它很容易满足大多数条件但遇到边缘情况,它也会从" 植物周期"中获取对象。与" 授粉"子主题。
如何根据上述条件进行查询以执行我想要的操作?
我将非常感谢任何帮助。
答案 0 :(得分:1)
实际上有“两个”问题没有解决这种情况。
第一个是作为单独的参数,没有什么可以说每个属性的值需要在同一个元素内,或者实际上如果特定组合实际出现在该元素中。要解决您在$elemMatch
表达式中使用$or
条件的问题:
var query = {
"$or": [
{ "topic": {
"$elemMatch": {
"topicName": "Reproduction in plants",
"subTopic": "Pollination"
}
}},
{ "topic": {
"$elemMatch": {
"topicName": "Plant Cycle",
"subTopic": "Photosynthesis"
}
}}
]
}
至少选择具有所需元素组合的文档。
但是没有任何内容可以从外部"topic"
或“内部”"subTopic"
数组中“过滤”多个结果。对于该任务,您需要聚合框架,因为这些功能不适用于基本投影:
var pipeline = [
// Still use the same match to filter possible documents
{ "$match": {
"$or": [
{ "topic": {
"$elemMatch": {
"topicName": "Reproduction in plants",
"subTopic": "Pollination"
}
}},
{ "topic": {
"$elemMatch": {
"topicName": "Plant Cycle",
"subTopic": "Photosynthesis"
}
}}
]
}},
// Filter the arrays for matches
{ "$project": {
"topics": {
"$filter": {
"input": {
"$map": {
"input": "$topic",
"as": "topic",
"in": {
"topicName": "$$topic.topicName",
"subTopic": {
"$filter": {
"input": "$$topic.subTopic",
"as": "subTopic",
"cond": {
"$or": [
{ "$and": [
{ "$eq": [ "$$topic.topicName", "Reproduction in plants" ] },
{ "$eq": [ "$$subTopic", "Pollination" ] }
]},
{ "$and": [
{ "$eq": [ "$$topic.topicName", "Plant Cycle" ] },
{ "$eq": [ "$$subTopic", "Photosynthesis" ] }
]}
]
}
}
}
}
}
},
"as": "topic",
"cond": {
"$and": [
{ "$or": [
{ "$eq": [ "$$topic.topicName", "Reproduction in plants" ] },
{ "$eq": [ "$$topic.topicName", "Plant Cycle" ] }
]},
{ "$ne": [ "$$topic.subTopic", [] ] }
]
}
}
}
}}
];
// API call to aggregate
Model.aggregate(pipeline,function(err,results) {
// results in here
});
这是使用阵列上的$filter
操作使用MongoDB 3.2的最佳方法。所以首先要注意,正在测试内部"subTopic"
元素是否匹配条件以及外部元素以决定返回哪些元素。它放在$map
内,以便将“已过滤”的内容返回到外部数组属性以供进一步检查。
然后“过滤”外部数组,以便仅返回匹配的"topicName"
值,当然只有"subTopic"
数组因过滤而不是“空”的地方。 / p>
可以在早期版本中执行此操作,但使用$unwind
的典型过程会变得非常耗时且成本高昂:
{ "$unwind": "$topic" },
{ "$unwind": "$topic.subTopic" },
{ "$match": {
"$or": [
{
"topic.topicName": "Reproduction in plants",
"topic.subTopic": "Pollination"
},
{
"topic.topicName": "Plant Cycle",
"topic.subTopic": "Photosynthesis"
}
]
}},
{ "$group": {
"_id": {
"_id": "$_id",
"topicName": "$topic.topicName",
},
"subTopic": { "$push": "$topic.subTopic" }
}},
{ "$group": {
"_id": "$_id._id",
"topic": {
"$push": {
"topicName": "$_id.topicName",
"subTopic": "$_id.subTopic"
}
}
}}
虽然看起来更简单,但由于$unwind
的性质,它的成本更高很多。当然,添加的每个聚合管道阶段都有自己的处理成本,而现代版本可以通过简单的$project
来实现。
如果你有一个早期版本,你最好的选择是使用所提到的初始“查询”,同时使用$or
和$elemMatch
,然后在代码中进行数组过滤。
除非你实际上需要在聚合管道中进一步处理这些数据,否则你将被困在该过程中以便“过滤”。
无论如何,你得到的结果是:
{
"topic": [
{
"topicName": "Reproduction in plants",
"subTopic": ["Pollination"]
},
{
"topicName": "Plant Cycle",
"subTopic": ["Photosynthesis"]
}
]
}
仅返回任何文档中“已过滤”的匹配元素。