首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对象在mongodb中的子数组筛选器查询中。

对象在mongodb中的子数组筛选器查询中。
EN

Stack Overflow用户
提问于 2016-03-22 21:58:58
回答 1查看 219关注 0票数 3

我和这件事斗争了一段时间,所以直截了当地说:

我在数据库中有一个对象

代码语言:javascript
复制
{
  topic: [
    {
      topicName: "Reproduction in plants",
      subTopic: ["Pollination", "Other Topic"]
    },
    {
      topicName: "Plant Cycle",
      subTopic: ["Pollination", "Photosynthesis"]
    },
  ]
}

我在这里试图解决的问题是如何生成满足以下条件的查询:

  1. 查找主题查询中的所有主题
  2. 对于每个主题,在主题中过滤带有子主题的结果。

因此,假设我想从一个查询中获得这个结果:

  1. 获取关于“植物繁殖”的主题,以及only的“授粉”子主题
  2. 获取“植物周期”的主题,only的“光合作用”子主题

在我目前的解决方案中:

代码语言:javascript
复制
filterQueries['topic.topicName'] = { $in: ["Reproduction in plants", "Plant Cycle"] };
filterQueries['topic.subTopic'] = { $in: ["Photosynthesis", "Pollination"] };

它很容易满足大多数条件,但遇到边缘情况,在那里,它也将从“植物周期”与“授粉”subTopic的对象。

如何根据上述条件进行查询以完成我想做的事情?

我会非常感谢你的帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-03-22 23:03:02

事实上,有“两个”问题,没有解决这样的条件。

第一种情况是,作为单独的参数,没有什么可说明每个属性的值必须在同一个元素中,或者实际上,如果特定的组合实际出现在该元素中。若要纠正在$elemMatch表达式中使用$or条件的问题,请执行以下操作:

代码语言:javascript
复制
 var query = {
     "$or": [
         { "topic": { 
             "$elemMatch": {
                 "topicName": "Reproduction in plants",
                 "subTopic": "Pollination"
             }
         }},
         { "topic": { 
             "$elemMatch": {
                 "topicName": "Plant Cycle",
                 "subTopic": "Photosynthesis"
             }
         }}
     ]
 }

至少在所需的元素中选择具有组合的文档。

但是没有任何东西可以“过滤”来自外部"topic"或“内部”"subTopic"数组的多个结果。对于该任务,您需要聚合框架,因为这些特性不能用于基本投影:

代码语言:javascript
复制
 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的典型过程会变得非常漫长和昂贵:

代码语言:javascript
复制
{ "$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,然后在代码中进行数组过滤。

当然,除非您确实需要在聚合管道中进一步处理该数据,否则您将被困在该流程中以进行“筛选”。

无论如何,您所得到的结果是:

代码语言:javascript
复制
{
  "topic": [
    {
      "topicName": "Reproduction in plants",
      "subTopic": ["Pollination"]
    },
    {
      "topicName": "Plant Cycle",
      "subTopic": ["Photosynthesis"]
    }
  ]
}

它只返回任何文档中“筛选”的匹配元素。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36166041

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档