Реализация SQL 'UNION ALL' в MongoDB

Есть две коллекции:

Продажи

{
  "_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
      }
   ]
}

Мне нужно получить продажи и транзакции в качестве «заголовка» для конкретной стороны (например, customerName, partyName) между двумя датами (например, saleDate, transactionDate), упорядоченными по дате; следующее:

[
  {
    "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
  }
]

Я исследовал и пробовал с агрегирование, $ поиск, но он не возвращает желаемое.

Переход с 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 есть запрос функции, и он «не решен».

Я хотел бы знать, есть ли способ для этого в драйвере mongoShell или MongoDB (mongoose / JS). Использование текущих стабильных версий MongoDB, nodejs, express и mongoose. Спасибо!

Не могли бы вы опубликовать то, что уже пробовали

Ashh 09.10.2018 10:19

Конечно. Это не полное доказательство, так как я просто пробовал. db.sales.aggregate ([{$ match: {"saleDate": {$ gte: ISODate ("2018-09-01"), $ lte: ISODate ("2018-09-10")}, "customerName": 'Acme Inc'}}, {$ lookup: {from: "transaction", localField: "customerName", foreignField: "partyName", as: "fromTransactions"}}, {$ replaceRoot: {newRoot: {$ mergeObjects: [ {$ arrayElemAt: ["$ fromTransactions", 0]}, "$$ ROOT"]}}}, {$ project: {saleDate: 1, invoiceNumber: 1, amount: 1, fromTransactions: 1}}])

Man In 09.10.2018 10:48

Это получение записей о продажах, каждая из которых документирована массивом транзакций с совпадающим именем customerName. Я знаю, что это совсем не правильно, но я пробовал это с агрегатом, но, похоже, это не то, что я хочу, поскольку мне нужно получать продажи и транзакции, упорядоченные по дате. Или, может быть, я ошибаюсь.

Man In 09.10.2018 10:53

Это может вам помочь stackoverflow.com/questions/52724403/…

Ashh 09.10.2018 19:17

@AnthonyWinzlet Имея в виду, ограничение BSON в 16 МБ на $ lookup предложенное вами решение подходит для временного использования. То же, что и в упомянутом вами вопросе, как насчет сортировки по дате (это не было упомянуто в ответе); мы должны отсортировать результирующую объединенную коллекцию «данных»? Я указал это в запросе, но без помощи. Какие-либо предложения.

Man In 10.10.2018 07:13

Ладно. теперь я могу отлично отсортировать его ... спроецированные 'saleDate' и 'transactionDate' как 'датированные', а затем указанные {"$ sort": {"date": 1}} в совокупном конвейере ... @ AnthonyWinzlet, не могли бы вы опубликовать ответ, включающий запрос из упомянутого вопроса, поскольку он был абсолютно полезен ... Так что я могу принять его как ответ :)

Man In 10.10.2018 08:33

Не могли бы вы опубликовать свой запрос, который сработал для вас? Мне нужно посмотреть

Ashh 11.10.2018 19:55

@AnthonyWinzlet Это почти то же самое, что вы предложили, за исключением «$ sort». Поскольку запрос не помещался в разделе комментариев здесь, я создал здесь скрипку jsfiddle.net/man_in/zpfay6on/1

Man In 12.10.2018 05:45

Большой!!! Ты понял. Написал ответ

Ashh 13.10.2018 06:23
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
9
4 431
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я так не думаю, что вы можете выполнить объединение двух разных коллекций в mongodb.

Однако вы можете получить данные из обеих коллекций с помощью q.all, а затем объединить их с помощью своей собственной функции или стороннего модуля, такого как lodash.

Единственный способ выполнить объединение в mongodb - это упомянутый здесь. https://docs.mongodb.com/manual/reference/operator/aggregation/setUnion/

Ваша ссылка касается логического объединения 2 массивов, а не реляционного объединения db.

Cyctemic 09.10.2018 09:39

Это не мой ответ. Я просто показываю ему, что mongodb его не поддерживает.

Sagar Chaudhary 09.10.2018 09:41

@SagarChaudhary Понятно. Я думал об этом, но мне было интересно, есть ли способ. Если это невозможно в оболочке MongoDB, то единственное, что у меня осталось, - это получение двух разных коллекций и их форматирование в соответствии с требованиями.

Man In 09.10.2018 10:57

Отказ от ответственности: метод, представленный ниже, не совсем рекомендуется. ;) Это особенно актуально при работе с большими коллекциями. Однако его можно использовать для достижения того же эффекта, что и SQL UNION ALL, начиная с MongoDB v3.6 и новее.

Даны сборник 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
})
Ответ принят как подходящий

Вы можете попробовать ниже агрегирование

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 }}
])

Хотите знать, поможет ли 'allowDiskUse: true' противостоять лимиту BSON?

Man In 13.10.2018 13:26

Пока у вас состояние $match, вам не о чем беспокоиться. allowDiskUse: true поможет только обрабатывать большой набор данных.

Ashh 13.10.2018 13:34

брат ты классный !! Благодарность!!!!!

Fernando Muñoz 04.12.2020 04:59

Другие вопросы по теме