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
}