MongoDB根据多个条件从阵列中选择

时间:2018-10-29 17:45:50

标签: mongodb mongodb-query

我具有以下结构(无法更改,这是我必须使用的结构):

{
        "_id" : ObjectId("abc123"),
        "notreallyusedfields" : "dontcare",
        "data" : [
                {
                        "value" : "value1",
                        "otherSomtimesInterestingFields": 1
                        "type" : ObjectId("asd123=type1"),
                },
                {
                        "value" : "value2",
                        "otherSometimesInterestingFields": 1
                        "type" : ObjectId("asd1234=type2"),
                },
                many others
        ]
}

因此,基本上,架构的字段位于数组内部,并且可以基于1个数组元素(1个架构字段,其值为数组中的1个元素)中的type字段进行标识。对我来说,这很奇怪,但是我是NoSQL的新手,所以这可能没问题。 (同样对于不同的数据,某些字段可能会丢失,并且不能保证数据数组中的元素顺序)

也许这样更容易理解: 表a:type1列| type2列|等等(这些都存储在上面的数组中)

我的问题是:如何根据条件选择多个字段?我的意思是(在SQL中):SELECT * FROM table WHERE type1 = value1 AND type2 = value2

我可以这样选择1: db.a.find( {"data.type":ObjectId("asd1234=type2"), "data.value":value2}).pretty()

但是我不知道该如何包含type1 = value1甚至更多条件。而且我认为这甚至不好,因为它可以匹配数组中的任何data.value字段,因此这并不意味着类型为type2的值必须为value2。

您将如何解决?

我当时想对1个条件进行1个查询,然后根据结果进行另一个查询。因此,类似聚合的管道,但是正如我所见,$ match不能在聚合中多次使用。我猜有一种管道这些命令的方法,但这很丑陋。 我想念什么?还是由于数据的结构,我不得不做这些奇怪的多重查询?

我也看过$ filter,但是那里的条件也适用于数组的任何元素。 (或者我做错了)

谢谢!

抱歉,如果我不够清楚!请询问,我可以详细说明。

(基本上我要基于此结构(Retrieve only the queried element in an object array in MongoDB collection来做的是这样的:如果形状为正方形,则过滤为蓝色,如果形状为圆形,则过滤为红色,===如果类型是type1的值必须是value1,如果type是type2的值必须是value2)

2 个答案:

答案 0 :(得分:1)

这可以像这样完成:

db.document.find( { $and: [ 
    { type:ObjectId('abc') }, 
    { data: { $elemMatch: { type: a, value: DBRef(...)}}},
    { data: { $elemMatch: { type: b, value: "string"}}}
] } ).pretty()

因此,您可以使用$添加任意数量的“条件”,然后可以指定一个元素必须具有类型a和值b,另一个元素必须具有类型b和值c ...

如果只想投影匹配的元素,则将聚合与过滤器一起使用:

db.document.aggregate([
{$match: { $and: [ 
    { type:ObjectId('a') }, 
    { data: { $elemMatch: { Type: ObjectId("b"), value: DBRef(...)}}},
    { data: { $elemMatch: { Type: ObjectId("c"), value: "abc"}}}
    ] }
},
{$project: {
      metadata: {
        $filter: {
            input: "$data",
            as: "data",
            cond: { $or: [
                {$eq: [ "$$data.Type", ObjectId("a") ] },
                {$eq: [ "$$data.Type", ObjectId("b") ] }]}
          }
        }
      }
}
]).pretty()

这非常丑陋,因此,如果有更好的方法,请发布!谢谢!

答案 1 :(得分:0)

如果您需要检索具有匹配的数组元素的文档    多个条件,则必须使用$elemMatch query operator

db.collection.find({
  data: {
      $elemMatch: {
        type: "type1",
        value: "value1"
      }
    }
  })

这将输出元素匹配的整个文档。

要仅输出数组中的第一个匹配元素,可以将其与$elemMatch projection operator组合。

db.collection.find({
  data: {
    $elemMatch: {
      type: "type1",
      value: "value1"
    }
  }
},
{
  data: {
    $elemMatch: {
      type: "type1",
      value: "value1"
    }
  }
})

警告,不要忘记将所需的所有其他字段投影到数据数组之外。

如果需要输出数组中所有匹配的元素,则必须在聚合$ project阶段使用$filter,如下所示:

db.collection.aggregate([
  {
    $project: {
      data: {
        $filter: {
          input: "$data",
          as: "data",
          cond: {
            $and: [
              {
                $eq: [
                  "$$data.type",
                  "type1"
                ]
              },
              {
                $eq: [
                  "$$data.value",
                  "value1"
                ]
              }
            ]
          }
        }
      }
    }
  }
])