我和这件事斗争了一段时间,所以直截了当地说:
我在数据库中有一个对象
{
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"] };它很容易满足大多数条件,但遇到边缘情况,在那里,它也将从“植物周期”与“授粉”subTopic的对象。
如何根据上述条件进行查询以完成我想做的事情?
我会非常感谢你的帮助。
发布于 2016-03-22 23:03:02
事实上,有“两个”问题,没有解决这样的条件。
第一种情况是,作为单独的参数,没有什么可说明每个属性的值必须在同一个元素中,或者实际上,如果特定的组合实际出现在该元素中。若要纠正在$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
});这是使用MongoDB 3.2对数组使用$filter操作的最优方法。因此,首先要注意的是,正在测试内部"subTopic"元素是否与外部元素匹配,以决定返回哪些条件。这被放置在一个$map中,以便将“过滤”内容返回到外部数组属性以供进一步检查。
然后对外部数组进行“筛选”,以便只返回匹配的"topicName"值,当然,只有在筛选的结果是"subTopic"数组不是“空”的情况下才返回。
在早期版本中可以这样做,但是使用$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"
}
}
}}虽然它看起来更简单,但由于所做的事情的本质,它是一个更昂贵的。当然,添加的每个聚合管道阶段都有自己的处理成本,而现代版本可以在一个简单的$project中做到这一点。
如果您有早期版本,最好的选择是使用前面提到的初始“查询”,同时使用$or和$elemMatch,然后在代码中进行数组过滤。
当然,除非您确实需要在聚合管道中进一步处理该数据,否则您将被困在该流程中以进行“筛选”。
无论如何,您所得到的结果是:
{
"topic": [
{
"topicName": "Reproduction in plants",
"subTopic": ["Pollination"]
},
{
"topicName": "Plant Cycle",
"subTopic": ["Photosynthesis"]
}
]
}它只返回任何文档中“筛选”的匹配元素。
https://stackoverflow.com/questions/36166041
复制相似问题