Mongodb 使用子字符串作为条件筛选子文档数组

Mongodb 使用子字符串作为条件筛选子文档数组,mongodb,mongoose,mapreduce,aggregation-framework,Mongodb,Mongoose,Mapreduce,Aggregation Framework,我的收藏: { title: 'Computers', maincategories:[ { title: 'Monitors', subcategories:[ { title: '24 inch', code: 'AFG' } ] } ] } 我想查询代码。代码只是第一部分,所以我想拥有包含给定搜索的所有子类别。因此AFG101将返回此子

我的收藏:

{
  title: 'Computers',
  maincategories:[
    {
       title: 'Monitors',
       subcategories:[
         {
            title: '24 inch',
            code: 'AFG'
         }
       ]
    }
  ]
}
我想查询代码。代码只是第一部分,所以我想拥有包含给定搜索的所有子类别。因此
AFG101
将返回此子类别

我的问题是:

module.exports = (req, res) => {
  var q = {
    'maincategories.subcategories': {
      $elemMatch: {
        code: 'AFG101'
      }
    }
  };

  var query = mongoose.model('TypeCategory').find(q, {'maincategories.$': 1, 'title': 1});

  query.exec((err, docs) => {
    res.status(200).send(docs);
  });
};
我的问题是:

  • 如何搜索字符串的一部分
    AFG101
    应返回属性为
    code
    且包含字符串任何部分的所有子类别。因此,在这种情况下,
    AFG
    将是一个热门话题。与此sql问题相同:

  • 如何投影子类别。当前查询返回所有子类别。我只想把打中的球还回去


  • 就像你的问题有两个部分一样,我可以想出两个不同的解决方案,但是我看不到一种方法把它们结合在一起

    对于第一部分,$where可以用来做一个反向正则表达式,但它是脏的,它是一个过度使用,并且它不能使用任何索引,因为$where在每个文档上运行

    db.TypeCategory.find({$where:function(){for(var i  in this.maincategories)
    {for(var j in this.maincategories[i].subcategories)
     {if("AFG101".indexOf(this.maincategories[i].subcategories[j].code)>=0)
      {return true}}}}},{"maincategories.subcategories.code":1})
    
    即使使用此选项,也需要进行两次边界检查,并且无法投影两级嵌套数组。MongoDB还不支持这种预测

    为此,我们可以进行聚合

    db.TypeCategory.aggregate([{$unwind:"$maincategories"},
     {$unwind:"$maincategories.subcategories"},
     {$match:{"maincategories.subcategories.code":"AFG"}},
     {$group:{_id:"$_id","maincategories":{$push:"$maincategories"}}}
    ])
    

    然而,我不认为有一种方法可以进行反向regex检入聚合,但我可能也错了。此外,这种聚合成本很高,因为有两个展开操作可能会导致非常大的集合的聚合内存限制溢出

    您可以使用$substr并执行此操作

    db.getCollection('cat').aggregate([
              {"$unwind" : "$maincategories"},
              {"$unwind" : "$maincategories.subcategories"},
              {"$project" :
                    {"maincategories" : 1,
                    "title":1,"sub" : {"$substr" :["$maincategories.subcategories.code",0,3]}}},
             {"$match" : {"sub" : "AFG"}},
             {"$project" : 
                     {"maincategories" : 1,
                      "title":1}
              }
        ])
    

    最好的方法是在MongoDB 3.4中使用字符串聚合操作符

    let code = "afg101";
    
    db.collection.aggregate([
        { "$project": { 
            "title": 1, 
            "maincategories": { 
                "$map": { 
                    "input": "$maincategories", 
                    "as": "mc", 
                    "in": { 
                        "$filter": { 
                            "input": "$$mc.subcategories", 
                            "as": "subcat", 
                            "cond": { 
                                "$gt": [ 
                                    { 
                                        "$indexOfCP": [ 
                                            code, 
                                            { "$toLower": "$$subcat.code" }
                                         ] 
                                    }, 
                                   -1 
                                ] 
                            } 
                        } 
                    } 
                } 
            } 
        }} 
    ])
    
    返回:

    {
        "_id" : ObjectId("582cba57e6f570d40d77b3a8"),
        "title" : "Computers",
        "maincategories" : [
            [
                {
                    "title" : "24 inch",
                    "code" : "AFG"
                }
            ]
        ]
    }
    
    你们可以阅读我对类似问题的其他回答,还有


    从3.2向后看,实现这一点的唯一方法是使用

    这会产生如下结果:

    {
    
        "results" : [
            {
                "_id" : ObjectId("582c9a1aa358615b6352c45a"),
                "value" : [
                    {
                        "title" : "Monitors",
                        "subcategories" : [
                            {
                                "title" : "24 inch",
                                "code" : "AFG"
                            }
                        ]
                    }
                ]
            }
        ],
        "timeMillis" : 15,
            "counts" : {
                "input" : 1,
                "emit" : 1,
                "reduce" : 0,
                "output" : 1
            },
        "ok" : 1
    }
    

    我想最好在查询Mongo之前将代码
    AFG101
    解析成相应的代码。@hyades,我不明白。我该怎么做?我想我知道你第一个问题想要什么。例如,您希望有多个带有“code:AFG1”、“code;AFG2”、“code:AFG3”、“code:ABC1”的文档。因此,当用户(无论何种类型)键入类似“AFG”的内容时,mongo将检索到其他代码字段中包含“AFG”的所有文档。如果是,请选中“regex”“在mongodb@阿尔贝托鲁比奥,不,换个方向。如果我的文档中的用户类型AFG101和属性代码为code:AFG,则应返回此代码。那么。。。都一样,不是吗$正则表达式将搜索您键入的字符串,并在文档中查找该字符串。这并不完全是你想要的,但你可以从那里开始。或者,如果您知道所有代码都以3个相同的字符开头,则生成并拆分,并从字符串中仅获取“AFG”。字符串的前3个字符。这就是我所有的,sry。你可以使用$group:{“\u id”:“$\u id”}stage和$push来创建数组
    {
    
        "results" : [
            {
                "_id" : ObjectId("582c9a1aa358615b6352c45a"),
                "value" : [
                    {
                        "title" : "Monitors",
                        "subcategories" : [
                            {
                                "title" : "24 inch",
                                "code" : "AFG"
                            }
                        ]
                    }
                ]
            }
        ],
        "timeMillis" : 15,
            "counts" : {
                "input" : 1,
                "emit" : 1,
                "reduce" : 0,
                "output" : 1
            },
        "ok" : 1
    }