嵌入式文档的$ divide元素-MongoDB聚合

时间:2020-01-16 19:09:52

标签: mongodb aggregation

我正在尝试创建一个聚合MongoDB查询。

数据结构:

{
    "object_name": Example,
    "values": [ {"name":"value1", "value":1}, 
                {"name":"value2", "value":10},
                {"name":"total", "value":105}
}

目标:找到对象名称,其中value1/total > 0.5value2/total > 0.25total > 100。 数据以这种方式进行结构,以在value_name和value字段上提供索引。

我尝试过的-与以下管道聚合:

$ match:过滤总计> 100的文档:

$match: { values: { $elemMatch: { value_name: "total", value: {$gte: 100 }

$ project:仅获取我们需要的value_names(有近200个不同的名称)

$project: {
            values: {
                $filter: {
                    input: "$values",
                    as: "value",
                    cond: { $or: [
                        { $eq: [ "$$value.name", "name1"] },
                        { $eq: [ "$$value.name", "name2"] },
                        { $eq: [ "$$value.name", "total"] },
                    ] }
                }
            },
            name: 1
        }

然后,{ $unwind: "$values" }

在这里,我可以从$group$divide: name1/total, name2/total,但是我一直在坚持如何获取这些值。 我不能简单地做stats.value:,因为它不知道我指的是哪个值。我相信$group不能$elemMatch也不能匹配名称。

如果有更简单的解决方案,我将非常感谢您的投入。

2 个答案:

答案 0 :(得分:1)

您可以使用$arrayToObject运算符将数组转换为对象,并添加tmp字段以轻松访问value1value2total

db.collection.aggregate([
  {
    $addFields: {
      tmp: {
        $arrayToObject: {
          $map: {
            input: "$values",
            as: "value",
            in: {
              k: "$$value.name",
              v: "$$value.value"
            }
          }
        }
      },
      name: 1
    }
  },
  {
    $match: {
      $expr: {
        $and: [
          {
            $gt: [
              {
                $divide: [
                  "$tmp.value1",
                  "$tmp.total"
                ]
              },
              0.5
            ]
          },
          {
            $gt: [
              {
                $divide: [
                  "$tmp.value2",
                  "$tmp.total"
                ]
              },
              0.25
            ]
          },
          {
            $gt: [
              "$tmp.total",
              100
            ]
          }
        ]
      }
    }
  },
  {
    $project: {
      tmp: 0
    }
  }
])

MongoPlayground

答案 1 :(得分:1)

请尝试:

  1. 我们正在过滤文档,其中values数组具有一个对象, name : totalvalue > 100
  2. 使用name : total添加对象 记录。
  3. 仅保留符合条件的对象 值数组中的value1/total > 0.5value2/total > 0.25
  4. 如果 该数组的大小大于1,则这两个条件是 见过。
  5. 最后只投影object_name

查询:

db.yourCollectionName.aggregate([{ $match: { values: { $elemMatch: { name: "total", value: { $gte: 100 } } } } }, 
    {
        $addFields: {
            totalValue: {
                $arrayElemAt: [{
                    $filter: {
                        input: "$values",
                        as: "item",
                        cond: { $eq: ["$$item.name", 'total'] }
                    }
                }, 0]
            }
        }
    },
    {
        $project: {
            values: {
                $filter: {
                    input: "$values",
                    as: "value",
                    cond: {
                        $or: [
                            { $cond: [{ $eq: ["$$value.name", "value1"] }, { $gt: [{ $divide: ["$$value.value", '$totalValue.value'] }, 0.5] }, false] },
                            { $cond: [{ $eq: ["$$value.name", "value2"] }, { $gt: [{ $divide: ["$$value.value", '$totalValue.value'] }, 0.25] }, false] }
                        ]
                    }
                }
            }, object_name: 1
        }
    }, {
        $match: {
            $expr: { $gt: [{ $size: "$values" }, 1] }
        }
    }, { $project: { object_name: 1, _id: 0 } }])

收集数据:

/* 1 */
{
    "_id" : ObjectId("5e20bd94d02e05b694d55fa5"),
    "object_name" : "Example",
    "values" : [ 
        {
            "name" : "value1",
            "value" : 1
        }, 
        {
            "name" : "value2",
            "value" : 10
        }, 
        {
            "name" : "total",
            "value" : 105
        }, 
        {
            "name" : "total1",
            "value" : 105
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5e20bdb1d02e05b694d56490"),
    "object_name" : "Example2",
    "values" : [ 
        {
            "name" : "value1",
            "value" : 1
        }, 
        {
            "name" : "value2",
            "value" : 10
        }, 
        {
            "name" : "total",
            "value" : 5
        }, 
        {
            "name" : "total1",
            "value" : 5
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("5e20d1b7d02e05b694d7c57a"),
    "object_name" : "Example3",
    "values" : [ 
        {
            "name" : "value1",
            "value" : 100
        }, 
        {
            "name" : "value2",
            "value" : 100
        }, 
        {
            "name" : "total",
            "value" : 200
        }, 
        {
            "name" : "total1",
            "value" : 205
        }
    ]
}

/* 4 */
{
    "_id" : ObjectId("5e20d1cad02e05b694d7c71c"),
    "object_name" : "Example4",
    "values" : [ 
        {
            "name" : "value1",
            "value" : 200
        }, 
        {
            "name" : "value2",
            "value" : 40
        }, 
        {
            "name" : "total",
            "value" : 200
        }, 
        {
            "name" : "total1",
            "value" : 205
        }
    ]
}

/* 5 */
{
    "_id" : ObjectId("5e20d1e2d02e05b694d7c933"),
    "object_name" : "Example5",
    "values" : [ 
        {
            "name" : "value1",
            "value" : 150
        }, 
        {
            "name" : "value2",
            "value" : 100
        }, 
        {
            "name" : "total",
            "value" : 200
        }, 
        {
            "name" : "total1",
            "value" : 205
        }
    ]
}

结果:

/* 1 */
{
    "object_name" : "Example5"
}
相关问题