Mongodb regex作为$filter在投影中
我试图找到(使用regexp)一个数组字段并仅返回该元素 这是我的数据Mongodb regex作为$filter在投影中,mongodb,mongoose,Mongodb,Mongoose,我试图找到(使用regexp)一个数组字段并仅返回该元素 这是我的数据 [ { "_id": "56d6e8bbf7404bd80a017edb", "name": "document1", "tags": [ "A area1", "B area2", "C area3" ] }, { "_id": "56d6e8bbf7404bd82d017ede", "name": "document2", "tags": [ "b_area3", "b_area4", "b
[
{
"_id": "56d6e8bbf7404bd80a017edb",
"name": "document1",
"tags": [
"A area1",
"B area2",
"C area3"
]
},
{
"_id": "56d6e8bbf7404bd82d017ede",
"name": "document2",
"tags": [
"b_area3",
"b_area4",
"b_area5"
]
}
]
我的问题
var query=new RegExp('^'+string, "i");
Model.find({tags:query},{'tags.$': 1}, function(err,data){
if(err) console.log(err);
res.json(data);
});
此查询仅选择标记字段(如我所需),但选择第一个元素。我需要与查询匹配的元素
编辑:我也尝试了mongodb聚合,$filter cond是错误的。我收到错误“MongoError:invalid operator$regex”
caseNote.aggregate([
{ $match: {tags:query}},
{ $project: {
tags: {$filter: {
input: 'tags',
as: 'item',
cond: {$regex: ['$$item', query]}
}}
}}
], function (err, result) {
if (err) {
console.log(err);
} else {
res.json(result);
}
});
caseNote
.aggregate({ $match: {tags: {$in:['area3']}}})
.unwind('tags')
.exec(function(err,d){
res.json(d);
});
EDIT2:on@zangw suggestion,这是mongoose版本,但不完整:标记字段很好(需要测试),但查询仍然返回整个文档。
caseNote.aggregate([
{ $match: {tags:query}},
{ $project: {
tags: {$filter: {
input: 'tags',
as: 'item',
cond: {$regex: ['$$item', query]}
}}
}}
], function (err, result) {
if (err) {
console.log(err);
} else {
res.json(result);
}
});
caseNote
.aggregate({ $match: {tags: {$in:['area3']}}})
.unwind('tags')
.exec(function(err,d){
res.json(d);
});
根据此问题,当前mongo版本的$regex
不能与cond
一起使用
也许你可以试试这个,通过$match
过滤区域3
,然后通过$group
获取所有匹配的标签,然后通过$project
删除\u id
caseNote.aggregate([{$unwind: '$tags'},
{$match: {tags: /area3/}},
{$group: {_id: null, tags: {$push: '$tags'}}},
{$project: {tags: 1, _id: 0}}])
.exec(function(err, tags) {
if (err)
console.log(err);
else
console.log(tags);
});
结果:
{ "tags" : [ "C area3", "b_area3" ] }
我就是这样解决的。如果查询可以解析为正则表达式,则投影不会添加到聚合中,而是在db请求之后发生。如果查询字符串是普通字符串,则添加投影
const { query } = req; // /rea/ or 'C area3'
const convertIfRegex = string => {
const parts = string.split('/')
let regex = string;
let options = '';
if (parts.length > 1) {
regex = parts[1];
options = parts[2];
} else {
return false
}
try {
return new RegExp(regex, options);
} catch (e) {
return null
}
};
const regex = convertIfRegex(queryString);
const aggregations = [{ $match: { tags:query } }]
if (!regex) {
aggregations.push({
$project: {
tags: {$filter: {
input: 'tags',
as: 'item',
cond: {$eq: ['$$item', query]}
}}
}
})
}
let result = await caseNote.aggregate(aggregations);
if (regex) {
result = result.reduce((acc, entry) => {
const tags = entry.tags.filter(({ tag }) => (
tag.match(regex)
))
if (tags.length) return [...acc, { ...entry, tags }];
return acc;
})
}
res.json(result)
根据@zangw的
根据这个问题,在$cond中使用$regex作为表达式,$regex不能与当前mongo版本的cond一起使用
MongoDB v4.1.11在中推出了新功能,该功能向聚合语言添加了三个新表达式$regexFind
、$regexFindAll
和$regexMatch
在您的示例中,可以使用表达式
Model.aggregate([
{
$project: {
tags: {
$filter: {
input: "$tags",
cond: {
$regexMatch: {
input: "$$this",
regex: query
}
}
}
}
}
}
])
@the.websurfer,我已经用测试数据更新了我的答案。您以前的代码与我的答案不符……我会更好地解释:我需要一个匹配查询的简单标记数组,类似于
[“C区域3”,“b区域3”]
。目前,我想通过查询无法直接完成这一任务。@Alfredpacino,你可以通过$group
来完成,请参考我的更新答案。@Alfredpacino,通过聚合末尾的$project
删除\u id>字段。我刚刚尝试过,它就像一个符咒,但是聚合不会删除重复项(我需要它)。我想我会在询问后自己移除,