首页 > 解决方案 > MongoDB 聚合 - 读取文档的运算符

问题描述

由于 Mongo 仅支持每个聚合管道(在第一阶段内)的一个 字段,这意味着您无法执行逻辑 AND,因为您无法获得多个搜索的结果。$text$match$and$text

// Fails due to "too many text expressions"
db.Employees.aggregate([
    {$match: {$and: [
        {$text: {$search: "senior"}},
        {$text: {$search: "manager"}}
    ]}}
])

因此,我需要执行多个单独$text的搜索,将结果合并到我的 NodeJS 代码中,然后将该结果集传递回聚合管道以进行进一步处理(例如$addFields$match$sort)。

有没有办法做类似...

let results1 = db.Employees.find({"$text":{"$search":"senior"}}, {"score":{"$meta":"textScore"}})
let results2 = db.Employees.find({"$text":{"$search":"manager"}}, {"score":{"$meta":"textScore"}})
let combinedResults = _.intersectionWith(results1, results2, _.isEqual)
let finalResults = /* pass combinedResults into aggregation pipeline and execute it */

与$out 运算符相反的东西,我在结果集中读取。

如果有帮助,我正在使用 NestJS 和 Mongoose。

标签: mongodbmongoosenestjsaggregationdata-ingestion

解决方案


限制$text你已经知道了,

如果您的字段有限,则有一个选项,使用$regexMatch,我不确定在多少字段中有文本索引,但是您可以将匹配条件与$and多个字段的运算符结合使用,

示例数据:

[
  { _id: 1, f1: "senior", f2: "manager" },
  { _id: 2, f1: "junior", f2: "manager" },
  { _id: 3, f1: "fresher", f2: "developer" },
  { _id: 4, f1: "manager", f2: "senior" }
]

聚合查询一:

  • $addFields在布尔值中添加新字段matchResult以匹配状态
db.collection.aggregate([
  {
    $addFields: {
      matchResult: {
        $and: [
  • 第一个$or条件匹配 if f1or f2fields match seniorthen return trueother wise returnfalse
          {
            $or: [
              { $regexMatch: { input: "$f1", regex: "senior", options: "x" } },
              { $regexMatch: { input: "$f2", regex: "senior", options: "x" } }
            ]
          },
  • 第二个$or条件匹配 if f1or f2fields match managerthen return trueother wise returnfalse
          {
            $or: [
              { $regexMatch: { input: "$f1", regex: "manager", options: "x" } },
              { $regexMatch: { input: "$f2", regex: "manager", options: "x" } }
            ]
          }
        ]
      }
    }
  },
  • $match条件返回结果matchResult等于true
  { $match: { matchResult: true } }
])

操场

聚合查询2:

  • 如果您不使用数组字段,那么这是一种排序方式,您可以直接将所有字段连接到一个字段上,这里我已经合并f1f2带有空格allField
db.collection.aggregate([
  {
    $addFields: {
      allField: { $concat: ["$f1", " ", "$f2"] }
    }
  },
  • 这将匹配$and两个单词匹配的条件,如果两者都为真,则返回真,否则为假
  {
    $addFields: {
      matchResult: {
        $and: [
          { $regexMatch: { input: "$allField", regex: "senior", options: "x" } },
          { $regexMatch: { input: "$allField", regex: "manager", options: "x" } }
        ]
      }
    }
  },
  • $match条件返回结果matchResult等于true
  { $match: { matchResult: true } }
])

操场

注意:这是有限字段的替代方法,但如果超过 5 个字段进行成像,则会影响查询的速度和性能。


推荐阅读