MongoDB 大于 x 的对象内数组内对象内字段的总和

MongoDB sum of fields inside objects inside an array that is inside of an object greater than x

//8。 isbn 至少售出 X 册的图书数量(X 的价值由您决定)。

图书示例


  {
    isbn: "0001",
    title: "Book1",
    pages: NumberInt("150"),
    price: NumberDecimal("321.2"),
    copies: NumberInt("3"),
    language: "english",
    author: ["Author1"],
    category: ["Space Opera"],
    genre: ["Genre-1", "Genre-2"],
    character: ["Character-1", "Character-2"],
  },

订单示例

{
    orderNo: "3",
    customerNo: "0003", 
    date: {
      day: NumberInt("25"),
      month: NumberInt("02"),
      year: NumberInt("2021"),
    },
    orderLine: [
      {
        isbn: "0006", 
        price: NumberDecimal("341.0"),
        amount: NumberInt("2"),
      },
      {
        isbn: "0007", 
        price: NumberDecimal("170.5"),
        amount: NumberInt("1"),
      },
    ],
  },

我的尝试 我相信我在小组赛阶段的管道内有一个错误。现在我至少需要有 isbn 和一个对象中出售的副本。

db.books.aggregate([ // editing this
  { $match : {} },
  {
    $lookup : 
      {
        from : "orders",
        pipeline : [
          {
            $group : 
            {
              _id: null,
              amount_total : { $sum : "$orderLine.amount" }
            }
          },
          { $project : { _id : 0,  amount_total : 1} }
        ],
        as : "amount"
      }
  },
  { $project : { _id : 0, isbn : 1, amount : 1} }
])

不知道为什么都是 0,我期待至少有一些不同的数字。

{
    "isbn": "0001",
    "amount": [
      {
        "amount_total": 0
      }
    ]
  },
  {
    "isbn": "0002",
    "amount": [
      {
        "amount_total": 0
      }
    ]
  },
  {
    "isbn": "0003",
    "amount": [
      {
        "amount_total": 0
      }
    ]
  },// and so on

$group 阶段中的 $sum 将对根字段和分组字段求和,但此处 orderLine 字段是一个数组,您需要在应用 [=12= 之前对该数字数组求和],表示嵌套$sum操作,

{
  $group: {
    _id: null,
    amount_total: {
      $sum: {
        $sum: "$orderLine.amount"
      }
    }
  }
}

Playground


尝试最终解决方案,

  • $match isbn orderLine.isbn 中的数组使用 $in 条件
  • $filter 迭代查找 orderLine 数组,并匹配 isbn,它将 return 过滤文档
  • $let 声明一个 orders 变量来保存 orderLine 的筛选文档,使用 $sum[=47= 对筛选数组中的 amount 求和]
  • $project显示必填字段,得到amount_total数组
  • 的总和
db.books.aggregate([
  {
    $lookup: {
      from: "orders",
      let: { isbn: "$isbn" },
      pipeline: [
        { $match: { $expr: { $in: ["$$isbn", "$orderLine.isbn"] } } },
        {
          $project: {
            _id: 0,
            amount_total: {
              $let: {
                vars: {
                  orders: {
                    $filter: {
                      input: "$orderLine",
                      cond: { $eq: ["$$this.isbn", "$$isbn"] }
                    }
                  }
                },
                in: { $sum: "$$orders.amount" }
              }
            }
          }
        }
      ],
      as: "amount"
    }
  },
  {
    $project: {
      _id: 0,
      isbn: 1,
      amount_total: { $sum: "$amount.amount_total" }
    }
  }
])

Playground

在您的查询中 $lookup 正在执行没有任何条件的连接操作,请尝试此查询:

db.books.aggregate([
    {
        $lookup: {
            from: "orders",
            let: { isbn: "$isbn" },
            pipeline: [
                { $unwind: "$orderLine" },
                {
                    $match: {
                        $expr: { $eq: ["$orderLine.isbn", "$$isbn"] }
                    }
                }
            ],
            as: "amount"
        }
    },
    { 
        $project: { 
            _id: 0, 
            isbn: 1, 
            amount_total: { $sum: "$amount.orderLine.amount" } 
        }
    }
]);

测试数据:

books collection:

/* 1 createdAt:3/12/2021, 10:41:13 AM*/
{
    "_id" : ObjectId("604af7f14b5860176c2254b7"),
    "isbn" : "0001",
    "title" : "Book1"
},

/* 2 createdAt:3/12/2021, 10:41:13 AM*/
{
    "_id" : ObjectId("604af7f14b5860176c2254b8"),
    "isbn" : "0002",
    "title" : "Book2"
}

orders collection:

/* 1 createdAt:3/12/2021, 11:10:51 AM*/
{
    "_id" : ObjectId("604afee34b5860176c2254ce"),
    "orderNo" : "1",
    "customerNo" : "0001",
    "orderLine" : [
        {
            "isbn" : "0001",
            "price" : 341,
            "amount" : 2
        },
        {
            "isbn" : "0002",
            "price" : 170.5,
            "amount" : 1
        },
        {
            "isbn" : "0003",
            "price" : 190.5,
            "amount" : 3
        }
    ]
},

/* 2 createdAt:3/12/2021, 11:10:51 AM*/
{
    "_id" : ObjectId("604afee34b5860176c2254cf"),
    "orderNo" : "3",
    "customerNo" : "0003",
    "orderLine" : [
        {
            "isbn" : "0001",
            "price" : 341,
            "amount" : 2
        },
        {
            "isbn" : "0002",
            "price" : 170.5,
            "amount" : 1
        },
        {
            "isbn" : "0003",
            "price" : 190.5,
            "amount" : 3
        }
    ]
}

输出:

/* 1 */
{
    "isbn" : "0001",
    "amount_total" : 4
},

/* 2 */
{
    "isbn" : "0002",
    "amount_total" : 2
}

显然,这正是我想要的。

db.books.aggregate([
  {
    $lookup: {
      from: "orders",
      let: { isbn: "$isbn" },   // Pass this variable to pipeline for Joining condition.
      pipeline: [
        { $unwind: "$orderLine" },
        {
          $match: {
            // Join condition.
            $expr: { $eq: ["$orderLine.isbn", "$$isbn"] }
          }
        },
        {
          $project: { _id: 0 , orderNo : 1,  "orderLine.amount": 1}
        }
      ],
      as: "amount"
    }
  }, { $project : { _id : 0, isbn : 1, amount_total : { $sum : "$amount.orderLine.amount" } } }
])