【问题标题】:regex as $filter in projection正则表达式作为投影中的 $filter
【发布时间】:2016-06-15 12:35:00
【问题描述】:

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

这是我的数据

  [
 {
"_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);
    }
});

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

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

【问题讨论】:

    标签: mongodb mongoose


    【解决方案1】:

    根据@zangw 的answer

    this ISSUE-SERVER-8892, 根据这个问题 Use $regex as the expression in a $cond, $regex cannot be used with cond for current mongo version.

    MongoDB v4.1.11ISSUE-SERVER-11947中推出了新功能,该功能在聚合语言中增加了三个新的表达式$regexFind$regexFindAll$regexMatch

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

    Model.aggregate([
      {
        $project: {
          tags: {
            $filter: {
              input: "$tags",
              cond: {
                $regexMatch: {
                  input: "$$this",
                  regex: query
                }
              }
            }
          }
        }
      }
    ])
    

    Playground

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        根据这个问题Use $regex as the expression in a $cond,对于当前的mongo版本,$regex 不能与cond 一起使用。

        也许你可以试试这个,过滤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" ] }
        

        【讨论】:

        • @the.websurfer,我已经用测试数据更新了我的答案。您以前的代码不符合我的回答...
        • 我会更好地解释:我需要一个与查询匹配的普通标签数组,例如["C area3","b_area3"]。目前我想没有办法直接通过查询来完成。
        • @alfredopacino,您可以通过$group 做到这一点,请参考我的更新答案。
        • @alfredopacino,在聚合结束时删除_id$project 的字段。
        • 我刚试过,它就像一个魅力,但聚合不会删除重复项(我需要那个)。我想我会在查询后自己删除,
        猜你喜欢
        • 2015-05-05
        • 1970-01-01
        • 2015-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-10-24
        • 2018-03-21
        • 1970-01-01
        相关资源
        最近更新 更多