正则表达式作为投影中的$ filter

时间:2016-03-02 15:06:03

标签: mongodb mongoose

我试图找到(使用正则表达式)一个数组字段并仅返回该元素

这是我的数据

  [
 {
"_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:无效的运营商$ 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);
    }
});

EDIT2:关于@zangw建议,这是mongoose版本,但它不完整:标签字段很好(需要测试),但查询仍然返回整个文档。

 caseNote
     .aggregate({ $match: {tags: {$in:['area3']}}})
     .unwind('tags')
     .exec(function(err,d){
         res.json(d);
     });

3 个答案:

答案 0 :(得分:5)

根据此问题Use $regex as the expression in a $cond$regex无法与cond一起用于当前的mongo版本。

也许您可以试试这个,过滤area3$match,然后通过$group获取所有匹配的代码,然后移除_id$project

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" ] }

答案 1 :(得分:0)

这就是我解决的方法。如果查询可以解析为正则表达式,则不会将投影添加到聚合中,而是在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)

答案 2 :(得分:0)

根据@zangw的answer

ISSUE-SERVER-8892,根据此问题使用$ regex作为$ cond中的表达式,对于当前的mongo版本,$ regex不能与cond一起使用。

MongoDB v4.1.11 已在ISSUE-SERVER-11947中启动了新功能,此功能为三个新表达式$regexFindAll$regexMatchModel.aggregate([ { $project: { tags: { $filter: { input: "$tags", cond: { $regexMatch: { input: "$$this", regex: query } } } } } } ]) 添加了新功能。聚合语言。

在您的示例中,您可以使用$regexMatch表达式,

Property 'country' does not exist on type 'ViewComponent'. Did you mean 'country$'?

Playground