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

MongoDB获取数组值匹配的所有文档,mongodb,Mongodb,我的文件结构如下: { "input": { "fields": [ { "name": "last_name_hebrew", "text": "test1", }, ], }, "output": { "fie

我的文件结构如下:

  {
    "input": {
      "fields": [
        {
          "name": "last_name_hebrew",
          "text": "test1",
        },
      ],
    },
    "output": {
      "fields": [
        {
          "name": "last_name_hebrew",
          "text": "test1"
        },
      ],
    },
  },
我想获取所有文档,其中字段的对象的名称为value
last\u name\u hebrew
,与
输出的值相同

例如,在给定的结构中,它将返回此文档,因为
input.fields.name
last\u name\u hebrew
,而
text
等于
output
中的
text

注意:我不能保证
输入
输出
中的
字段
数组将在数组中包含
name:last\u name\u hebrew

我怎样才能做到

这是我第一次尝试强制数组中的文档名为
last\u name\u hebrew

db.collection.find({
  "input.fields": {
    $elemMatch: {
      "name": "last_name_hebrew"
    }
  },
  "output.fields": {
    $elemMatch: {
      "name": "last_name_hebrew"
    }
  },
  
})

但是现在我需要比较
文本
值。

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

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
        ]
      }
    }
  }
])
需要注意的一点是,此查询对
输出.fields.name
没有限制(因为它不是必需的),如果确实需要名称匹配,则可以在
$setIsSubset
操作符中删除
.text
字段。

  • 您使用
    $elemMatch
    的前2个条件是正确的
  • 添加表达式匹配,首先使用
    $filter
    input
    中查找具有
    姓氏\u希伯来语
    名称的匹配元素,然后使用
    $arrayElemAt
    从过滤结果中获取第一个元素,对
    输出
    字段执行相同的过程,然后使用
    $eq
    匹配两个对象


第二个选项:如果您想使用更具体的方法来匹配精确的两个字段
name
text
,这两个字段只需添加
$let
操作符即可从过滤器返回字段

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
    检查返回结果是否不为[]空

输出.字段.名称可以是什么吗?听起来这不是一个约束。@TomSlabbaert是的,它可以是任何东西。我正在寻找那些
name
值为
last\u name\u hebrew
的人,我打开了你的游乐场链接,你的查询似乎是错误的,因为输入的名称是
last\u name\u hebrew
test1
文本,但你的
输出
字段中没有任何匹配项。那里匹配的名称是
last\u name\u hebrew
,但是文本是
test21
,它不等于
test1
,首先您可以在那里更改代码,其次
输出
输入
是数组,因为你没有提供关于有多少个项目可以在那里的扩展信息,所以我假设它可以超过1个。你是回答的人。如果你的解决方案是错误的,你需要改变它。您是否知道您的解决方案是错误的?正如评论中所述-此解决方案不符合我的要求。。
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" }
        }
      }
    ]
  }
})
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"] }
                    ]
                  }
                }
              },
              []
            ]
          }
        }
      },
      []
    ]
  }
})