Mongodb聚合-在连接数组中按root _id查找和过滤

发布于 2025-01-16 22:30:52 字数 1492 浏览 1 评论 0原文

我有聚合,如下所示。聚合在发票表上进行。我只是加入通知,然后尝试按通知过滤发票。

我想要获取尚未发送通知的发票。换句话说 - 给我未加入状态“SENT”、服务类型“EMAIL”、类型“BILLING_INVOICE”并分配发票的通知的发票。主要问题是属性发票和对 _id 的引用。我也尝试通过 $_id 或 $data._id 进行引用,但没有任何效果。什么是正确的解决方案?谢谢。

正确运行的示例

发票

[{_id: 123, order: 333}]

通知

[{_id: 345, order: 333, state: SENT, serviceType: EMAIL, type: BILLING_INVOICE, invoice: 123}]

退回的发票 - [{_id: 123}]

发票

[{_id: 123, order: 333}]

通知

[{_id: 345, order: 333, state: SENT, serviceType: EMAIL, type: BILLING_INVOICE, invoice: 555}]  

退回的发票 - []

let invoices = await this.invoiceDao.getModel().aggregate([
    // join notifications from order
    {
        $lookup: {
            from: "customer.notifications",
            localField: "order",
            foreignField: "order",
            as: "notifications"
        }
    },
    {
        $match: {
            "notifications": {
                // notification of billing invoice MUST NOT be sent
                $not: {
                    $elemMatch: {
                        "state": NotificationState.SENT,
                        "serviceType": NotificationServiceType.EMAIL,
                        "type": NotificationType.BILLING_INVOICE,
                        "invoice": "$$_id"
                    }
                }
            }
        }
    }
]);

I have aggregation as you can see below. The aggregation works over Invoices table. I just join notifications and then try to filter invoices by notifications.

I would like to get invoices for which notifications have not yet been sent. Other words - give me invoices which have not joined notification with state "SENT", serviceType "EMAIL", type "BILLING_INVOICE" and assigned the invoice. The main problem is the attribute invoice and referencing to _id. I also tried reference by $_id or $$data._id, but nothing works. What is right solution? Thank you.

Example of proper functioning

Invoices

[{_id: 123, order: 333}]

Notifications

[{_id: 345, order: 333, state: SENT, serviceType: EMAIL, type: BILLING_INVOICE, invoice: 123}]

Returned invoices - [{_id: 123}]

Invoices

[{_id: 123, order: 333}]

Notifications

[{_id: 345, order: 333, state: SENT, serviceType: EMAIL, type: BILLING_INVOICE, invoice: 555}]  

Returned invoices - []

let invoices = await this.invoiceDao.getModel().aggregate([
    // join notifications from order
    {
        $lookup: {
            from: "customer.notifications",
            localField: "order",
            foreignField: "order",
            as: "notifications"
        }
    },
    {
        $match: {
            "notifications": {
                // notification of billing invoice MUST NOT be sent
                $not: {
                    $elemMatch: {
                        "state": NotificationState.SENT,
                        "serviceType": NotificationServiceType.EMAIL,
                        "type": NotificationType.BILLING_INVOICE,
                        "invoice": "$_id"
                    }
                }
            }
        }
    }
]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

記柔刀 2025-01-23 22:30:52

我不太清楚您的条件,您喜欢通过 OR 还是 AND 组合条件?

解决方案可能如下所示:

db.invoices.aggregate([
   {
      $lookup: {
         from: "notifications",
         localField: "order",
         foreignField: "order",
         as: "notifications"
      }
   },
   {
      $set: {
         notifications: {
            $filter: {
               input: "$notifications",
               cond: {
                  $not: {
                     $and: [
                        { $eq: ["$this.serviceType", "EMAIL"] },
                        { $eq: ["$this.state", "SENT"] },
                        { $eq: ["$this.type", "BILLING_INVOICE"] }
                     ]
                  }
               }
            }
         }
      }
   },
   { $match: { notifications: [] } }
])

Mongo Playground

您可以过滤 $lookup< 中已有的通知/code>,可能会提供更好的性能:

db.invoices.aggregate([
   {
      $lookup: {
         from: "notifications",
         let: { invoice_order: "$order" },
         pipeline: [
            {
               $match: {
                  serviceType: { $ne: "EMAIL" },
                  state: { $ne: "SENT" },
                  type: { $ne: "BILLING_INVOICE" }
               }
            },
            { $match: { $expr: { $eq: ["$order", "$invoice_order"] } } } // join condition               
         ],
         as: "notifications"
      }
   }
])

Your conditions are not fully clear to me do you like to combine the conditions by OR or AND?

Solution could be like this one:

db.invoices.aggregate([
   {
      $lookup: {
         from: "notifications",
         localField: "order",
         foreignField: "order",
         as: "notifications"
      }
   },
   {
      $set: {
         notifications: {
            $filter: {
               input: "$notifications",
               cond: {
                  $not: {
                     $and: [
                        { $eq: ["$this.serviceType", "EMAIL"] },
                        { $eq: ["$this.state", "SENT"] },
                        { $eq: ["$this.type", "BILLING_INVOICE"] }
                     ]
                  }
               }
            }
         }
      }
   },
   { $match: { notifications: [] } }
])

Mongo Playground

You can filter notifications already inside the $lookup, might give better performance:

db.invoices.aggregate([
   {
      $lookup: {
         from: "notifications",
         let: { invoice_order: "$order" },
         pipeline: [
            {
               $match: {
                  serviceType: { $ne: "EMAIL" },
                  state: { $ne: "SENT" },
                  type: { $ne: "BILLING_INVOICE" }
               }
            },
            { $match: { $expr: { $eq: ["$order", "$invoice_order"] } } } // join condition               
         ],
         as: "notifications"
      }
   }
])
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文