首页 > 解决方案 > 在 mongodb 中二级展开后如何进行匹配?

问题描述

我正在开发一个使用 MongoDB 作为数据库的软件。我有一个这样的集合(这只是一个文件)

{
    "_id" : ObjectId("5aef51e0af42ea1b70d0c4dc"),    
    "EndpointId" : "89799bcc-e86f-4c8a-b340-8b5ed53caf83",    
    "DateTime" : ISODate("2018-05-06T19:05:04.574Z"),
    "Url" : "test",
    "Tags" : [ 
        {
            "Uid" : "E2:02:00:18:DA:40",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:04.574Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-98")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-65")
                }
            ]
        }, 
        {
            "Uid" : "12:3B:6A:1A:B7:F9",
            "Type" : 1,
            "DateTime" : ISODate("2018-05-06T19:05:04.574Z"),
            "Sensors" : [ 
                {
                    "Type" : 1,
                    "Value" : NumberDecimal("-95")
                }, 
                {
                    "Type" : 2,
                    "Value" : NumberDecimal("-59")
                }, 
                {
                    "Type" : 3,
                    "Value" : NumberDecimal("12.939770381907275")
                }
            ]
        }
    ]
}

我想在它上面运行这个查询。

db.myCollection.aggregate([
  { $unwind: "$Tags" },
  {
    $match: {
      $and: [
        {
          "Tags.DateTime": {
            $gte: ISODate("2018-05-06T19:05:02Z"),
            $lte: ISODate("2018-05-06T19:05:09Z"),
          },
        },
        { "Tags.Uid": { $in: ["C1:3D:CA:D4:45:11"] } },
      ],
    },
  },
  { $unwind: "$Tags.Sensors" },
  { $match: { "$Tags.Sensors.Type": { $in: [1, 2] } } },
  {
    $project: {
      _id: 0,
      EndpointId: "$EndpointId",
      TagId: "$Tags.Uid",
      Url: "$Url",
      TagType: "$Tags.Type",
      Date: "$Tags.DateTime",
      SensorType: "$Tags.Sensors.Type",
      Value: "$Tags.Sensors.Value",
    },
  },
])

问题是,第二个匹配项(检查$Tags.Sensors.Type)不起作用并且不会影响查询结果。

我该如何解决?

如果这不是正确的方法,那么运行这些条件的正确方法是什么?

标签: mongodbmongodb-queryaggregation-framework

解决方案


$match阶段接受不带前导$符号的字段名称。您在第一$match阶段正确地做到了这一点,但在您编写的第二阶段$Tags.Sensors.Type。只需删除前导$符号即可使您的查询正常工作。

请注意,整个事情可以稍微简化(并且一些美化也不会受到伤害):

  1. 您不需要$and在您的示例中使用,因为如果您在过滤器中指定多个标准,则默认情况下会使用它。

  2. $in您用于过滤器的可以Tags.Sensors.Type是一种简单:的相等运算符,除非您在可接受值列表中有多个元素。

  3. 在这个阶段,除非字段的顺序很重要,否则您可以使用语法$project而不是(某种)重复相同的字段名称。<field>: 1

所以最终的查询将是这样的。

db.myCollection.aggregate([
{
    "$unwind" : "$Tags"
},
{
    "$match" : {
        "Tags.DateTime" : { "$gte" : ISODate("2018-05-06T19:05:02Z"), "$lte" : ISODate("2018-05-06T19:05:09Z") },
        "Tags.Uid" : { "$in" : ["C1:3D:CA:D4:45:11"] }
    }
}, {
    "$unwind" : "$Tags.Sensors"
}, { 
    "$match" : {
        "Tags.Sensors.Type" : { "$in" : [1,2] } 
    }
},
{
    "$project" : { 
        "_id" : 0,
        "EndpointId" : 1, 
        "TagId" : "$Tags.Uid",
        "Url" : 1,
        "TagType" : "$Tags.Type", 
        "Date" : "$Tags.DateTime", 
        "SensorType" : "$Tags.Sensors.Type", 
        "Value" : "$Tags.Sensors.Value" 
    }
}])

推荐阅读