首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB获取数组值匹配的所有文档

MongoDB获取数组值匹配的所有文档
EN

Stack Overflow用户
提问于 2021-03-25 14:35:50
回答 2查看 264关注 0票数 3

我的文件结构如下:

代码语言:javascript
复制
  {
    "input": {
      "fields": [
        {
          "name": "last_name_hebrew",
          "text": "test1",
        },
      ],
    },
    "output": {
      "fields": [
        {
          "name": "last_name_hebrew",
          "text": "test1"
        },
      ],
    },
  },

我希望获得所有文档,其中字段的对象具有值last_name_hebrew的名称,与output.fieldstext值相同。

例如,在给定的结构中,它将返回这个文档,因为input.fields.namelast_name_hebrewtext等于output中的text

注意,我不能保证fields数组在inputoutput中都会有name: last_name_hebrew在数组中。

我怎样才能做到呢?

这是我第一次尝试使用name of last_name_hebrew强制数组拥有文档。

代码语言:javascript
复制
db.collection.find({
  "input.fields": {
    $elemMatch: {
      "name": "last_name_hebrew"
    }
  },
  "output.fields": {
    $elemMatch: {
      "name": "last_name_hebrew"
    }
  },
  
})

但是现在我需要比较text值。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-04-04 12:47:01

  • 使用$elemMatch的第一个2条件是正确的
  • 添加表达式匹配,首先使用last_name_hebrewinput查找具有$filter名称的匹配元素,然后使用$arrayElemAt从筛选结果中获取第一个元素,对output字段进行相同的处理,然后使用$eq匹配两个对象。
代码语言:javascript
复制
db.collection.find({
  "input.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  "output.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  $expr: {
    $eq: [
      {
        $arrayElemAt: [
          {
            $filter: {
              input: "$input.fields",
              cond: { $eq: ["$$this.name", "last_name_hebrew"] }
            }
          },
          0
        ]
      },
      {
        $arrayElemAt: [
          {
            $filter: {
              input: "$output.fields",
              cond: { $eq: ["$$this.name", "last_name_hebrew"] }
            }
          },
          0
        ]
      }
    ]
  }
});

游乐场

第二个选项:如果您想要更具体地匹配确切的2个字段,nametext都需要添加$let运算符从过滤器返回字段,

代码语言:javascript
复制
db.collection.find({
  "input.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  "output.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  $expr: {
    $eq: [
      {
        $let: {
          vars: {
            input: {
              $arrayElemAt: [
                {
                  $filter: {
                    input: "$input.fields",
                    cond: { $eq: ["$$this.name", "last_name_hebrew"] }
                  }
                },
                0
              ]
            }
          },
          in: { name: "$$input.name", text: "$$input.text" }
        }
      },
      {
        $let: {
          vars: {
            output: {
              $arrayElemAt: [
                {
                  $filter: {
                    input: "$output.fields",
                    cond: { $eq: ["$$this.name", "last_name_hebrew"] }
                  }
                },
                0
              ]
            }
          },
          in: { name: "$$output.name", text: "$$output.text" }
        }
      }
    ]
  }
})

游乐场

第三个选项:为了更具体地检查循环中的两个字段,

  • 首先,使用$filter按输入字段中的名称过滤匹配的元素
  • 通过上面的过滤器会产生另一个过滤器
  • 筛选以匹配输出字段中的名称和文本字段,如果其不为[]空,则返回筛选结果。
  • 检查返回结果的$ne不为[]空
代码语言:javascript
复制
db.collection.find({
  "input.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  "output.fields": { $elemMatch: { "name": "last_name_hebrew" } },
  $expr: {
    $ne: [
      {
        $filter: {
          input: {
            $filter: {
              input: "$input.fields",
              cond: { $eq: ["$$this.name", "last_name_hebrew"] }
            }
          },
          as: "i",
          cond: {
            $ne: [
              {
                $filter: {
                  input: "$output.fields",
                  cond: {
                    $and: [
                      { $eq: ["$$this.name", "$$i.name"] },
                      { $eq: ["$$this.text", "$$i.text"] }
                    ]
                  }
                }
              },
              []
            ]
          }
        }
      },
      []
    ]
  }
})

游乐场

票数 1
EN

Stack Overflow用户

发布于 2021-03-25 15:56:02

您必须使用聚合管道来实现这一点,有几种方法可以这样做,下面是一个示例:

代码语言:javascript
复制
db.collection.aggregate([
  {
    $match: {
      $expr: {
        $gt: [
          {
            $size: {
              $filter: {
                input: "$input.fields",
                as: "inputField",
                cond: {
                  $and: [
                    {
                      $eq: [
                        "$$inputField.name",
                        "last_name_hebrew"
                      ]
                    },
                    {
                      "$setIsSubset": [
                        [
                          "$$inputField.text"
                        ],
                        "$output.fields.text"
                      ]
                    }
                  ]
                }
              }
            }
          },
          0
        ]
      }
    }
  }
])

蒙戈游乐场需要注意的一点是,对于这个查询,对output.fields.name没有任何限制(因为它不是必需的),如果您确实要求名称匹配,那么您可以在$setIsSubset操作符中删除.text字段。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66801727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档