有两个集合:
销售
{
"_id" : ObjectId("5ba0bfb8d1acdc0de716e839"),
"invoiceNumber" : 1,
"saleDate" : ISODate("2018-09-01T00:00:00.000Z"),
"totalTaxAmount" : 613,
"subTotalAmount" : 2000,
"totalAmount" : 2613,
"balance" : 2613,
"financialYear" : "2018-2019",
"modeOfPayment" : "Digital Transfer",
"customerName": "Acme Inc"
}
交易
{
"_id" : ObjectId("5bbb4e131fb8af0dc645212d"),
"transactionNumber" : 1
"transactionDate" : ISODate("2018-09-03T00:00:00.000Z"),
"transactionType" : "Income",
"partyName" : "Acme Inc",
"transactionMode" : "Digital Transfer",
"amount" : 2613,
"paidItems" : [
{
"orderId" : "5b90a7d62bb5a21be4ff97e3",
"invoiceNumber" : "1",
"orderType" : "sale",
"totalAmount" : 2613,
"balance" : 613,
"payingAmount" : 2000
}
]
}
我需要按日期排序的两个日期(即saleDate,transactionDate)之间检索特定方(即customerName,partyName)的销售和交易作为“标题”;如下:
[
{
"date": ISODate("2018-09-01T00:00:00.000Z"),
"heading": "Sale",
"particulars": "Invoice # 1",
"amount": 2613
},
{
"date": ISODate("2018-09-03T00:00:00.000Z"),
"heading": "Payment by Digital Transfer",
"particulars": "Transaction # 1",
"amount": 2000
}
]
我研究并尝试了aggregation,$lookup,但没有返回期望的结果。
从SQL切换到MongoDB。在SQL中,以下查询工作正常:
select sale_date as dated, 'Sale' as heading, 'Invoice # ' +
convert(varchar(12),invoice_number) as particulars,
convert(varchar(12), total) as amount,
from sales where sale_date between @from_date AND @to_date AND
customer_name=@customer_name
UNION ALL
select transaction_date as dated, 'Payment by ' + transaction_mode as
heading, 'Transaction # ' + convert(varchar(12), transaction_id) as
particulars, convert(varchar(12), amount) as amount from transactions
where transaction_date between @from_date AND @to_date AND
party_name=@customer_name
order by dated DESC
在MongoDB社区中有一个feature request档案,它是“未解决的”。
我想知道mongoShell或MongoDB驱动程序(mongoose / JS)中对此有什么办法。使用当前稳定的MongoDB,nodejs,express和mongoose版本。谢谢!
答案 0 :(得分:3)
我不认为您可以在mongodb中对2个不同的集合执行联合。
但是,您可以使用q.all从这两个集合中获取数据,然后使用自己的函数从它们中进行合并,或者可以是像lodash这样的第三方模块。
您可以在mongodb中执行联合的唯一方法是此处所述。 https://docs.mongodb.com/manual/reference/operator/aggregation/setUnion/
答案 1 :(得分:2)
您可以尝试以下汇总
db.sales.aggregate([
{ "$limit": 1 },
{ "$facet": {
"collection1": [
{ "$limit": 1 },
{ "$lookup": {
"from": "sales",
"pipeline": [
{ "$match": {
"date": { "$gte": ISODate("2018-09-01"), "$lte": ISODate("2018-09-10") },
"customer.name": customerName
}},
{ "$project": {
"_id":0, "dated": "$saleDate", "heading": "Sale", "particulars": "$invoiceNumber",
"amount": "$totalAmount", "modeOfPayment": null
}}
],
"as": "collection1"
}}
],
"collection2": [
{ "$limit": 1 },
{ "$lookup": {
"from": "transactions",
"pipeline": [
{ "$match": {
"transactionDate": { "$gte": ISODate("2018-09-01"), "$lte": ISODate("2018-09-10") },
"userId": userId, "partyName": customerName
}},
{ "$project": {
"_id":0, "dated": "$transactionDate", "heading": "Payment","particulars": "$transactionNumber",
"amount": "$amount", "paymentMode": "$transactionMode"
}}
],
"as": "collection2"
}}
]
}},
{ "$project": {
"data": {
"$concatArrays": [
{ "$arrayElemAt": ["$collection1.collection1", 0] },
{ "$arrayElemAt": ["$collection2.collection2", 0] },
]
}
}},
{ "$unwind": "$data" },
{ "$replaceRoot": { "newRoot": "$data" } },
{ "$sort": { "dated": -1 }}
])
答案 2 :(得分:1)
免责声明:下列技术并非完全可取。 ;)尤其是在处理大型馆藏时。但是,它可用于实现与MongoDB v3.6及更高版本中的SQL UNION ALL
相同的效果。
给出一个集合first
和一个集合second
:
db.first.aggregate([{
$group: { // create an array to hold all documents of the first collection
"_id": null,
"first": {
$push: "$$ROOT"
}
}
}, {
$lookup: { // perform some kind of ridiculous lookup which will return all documents from the second collection in an array
from: "second",
let: { /* we do not need any variables */ },
pipeline: [ { $match: { /* this filter will match every document */ } } ],
as: "second"
}
}, {
$project: {
"all": { $concatArrays: [ "$first", "$second" ] } // merge the two collections
}
}, {
$unwind: "$all" // flatten the resulting array
}, {
$replaceRoot: { "newRoot": "$all" } // move content of "all" field all the way up
}], {
allowDiskUse: true // make sure we do not run into memory issues
})