У меня есть коллекция ниже, и я использую агрегацию MongoDB для получения результата (где я объединяю все позиции заказа для заказа) и пытаюсь объединиться с другой коллекцией (order
).
[
{
"order_line_item_id": 1,
"order_id": 100,
"products": [
{
"name": "Shoe",
"hasDefect": "YES"
},
{
"name": "Pant",
"hasDefect": "NO"
},
{
"name": "Shirt",
"hasDefect": "NOT_SURE"
}
]
},
{
"order_line_item_id": 2,
"order_id": 100,
"products": [
{
"name": "Shoe",
"hasDefect": "YES"
},
{
"name": "Pant",
"hasDefect": "YES"
},
{
"name": "Shirt",
"hasDefect": "YES"
}
]
},
{
"order_line_item_id": 3,
"order_id": 101,
"products": [
{
"name": "Shoe",
"hasDefect": "YES"
},
{
"name": "Pant",
"hasDefect": "NO"
},
{
"name": "Shirt",
"hasDefect": "NOT_SURE"
}
]
}
]
Я использую приведенную ниже агрегацию для достижения результата
db.collection.aggregate([
{
$match: {
order_id: {
$eq: 100
}
}
},
{
$unwind: "$products"
},
{
$match: {
"products.name": {
$eq: "Pant"
}
}
},
{
$group: {
_id: {
order_id: "$order_id",
productName: "$products.name"
},
hasDefects: {
$push: "$products.hasDefect"
},
products: {
$push: "$products"
}
}
},
{
$set: {
hasDefect: {
$switch: {
branches: [
{
case: {
$allElementsTrue: {
$map: {
input: "$hasDefects",
as: "d",
in: {
$eq: [
"$$d",
"YES"
]
}
}
}
},
then: "YES"
},
{
case: {
$in: [
"NO",
"$hasDefects"
]
},
then: "NO"
},
{
case: {
$in: [
"NOT_SURE",
"$hasDefects"
]
},
then: "NOT_SURE"
}
],
default: "<DEFAULT>"
}
}
}
},
{
$group: {
_id: "$_id.order_id",
order_id: {
"$first": "$_id.order_id"
},
products: {
$push: {
name: "$_id.productName",
hasDefect: "$hasDefect",
lastModified: {
$dateToString: {
date: new Date(),
timezone: "America/New_York"
}
}
}
}
}
},
{
$unset: [
"_id"
]
},
{
$merge: {
into: "order_res",
on: [ "order_id" ],
whenMatched: "replace",
whenNotMatched: "insert"
}
}
])
Результатом может быть новый документ или обновление одного из продуктов в документе order
(как показано ниже).
[
{
"order_id": 100,
"products": [
{
"name": "Shoe",
"hasDefect": "YES"
},
]
}
]
Я использую этап агрегирования слиянием для вставки/обновления в другую коллекцию mongoDB.
{ $merge: { into: "order", on: "order_id", whenMatched: "replace", whenNotMatched: "insert" }}
Проблема в том, что это операция обновления, и в заказе есть предыдущие продукты, которые заменяют все существующие продукты на новые. Например, если в заказе есть указанный ниже документ, он должен обновить только товар «Обувь».
[
{
"order_id": 100,
"products": [
{
"name": "Shoe",
"hasDefect": "NO"
},
{
"name": "Pant",
"hasDefect": "NO"
},
{
"name": "Shirt",
"hasDefect": "NOT_SURE"
}
]
}
]
🤔 А знаете ли вы, что...
MongoDB предоставляет средства для миграции данных из других СУБД в MongoDB...
Вы можете использовать $mergeObjects вместо $merge, чтобы создать новую коллекцию с нужными документами. Пожалуйста, дайте мне знать, если приведенный ниже запрос работает для вас:
[
{
$match: {
order_id: 100
}
},
{
$unwind: "$products"
},
{
$match: {
"products.name": "Pant"
}
},
{
$group: {
_id: {
order_id: "$order_id",
productName: "$products.name"
},
hasDefects: {
$push: "$products.hasDefect"
}
}
},
{
$set: {
hasDefect: {
$switch: {
branches: [
{
case: {
$allElementsTrue: {
$map: {
input: "$hasDefects",
as: "d",
in: {
$eq: ["$$d", "YES"]
}
}
}
},
then: "YES"
},
{
case: {
$in: ["NO", "$hasDefects"]
},
then: "NO"
},
{
case: {
$in: ["NOT_SURE", "$hasDefects"]
},
then: "NOT_SURE"
}
],
default: "<DEFAULT>"
}
}
}
},
{
$project: {
order_id: "$_id.order_id",
productName: "$_id.productName",
hasDefect: "$hasDefect",
lastModified: {
$dateToString: {
date: new Date(),
timezone: "America/New_York"
}
}
}
},
{
$merge: {
into: "order",
whenMatched: [
{
$addFields: {
products: {
$map: {
input: "$$ROOT.products",
as: "product",
in: {
$cond: {
if: {
$eq: ["$$product.name", "$productName"]
},
then: {
$mergeObjects: [
"$$product",
{ hasDefect: "$hasDefect" }
]
},
else: "$$product"
}
}
}
}
}
}
],
whenNotMatched: "insert"
}
}
]
С наилучшими пожеланиями Асавари
Ссылаясь на вопрос из моего предыдущего ответа,
Вы можете предоставить конвейер агрегации для WhenMatched.
Важным ключом является ссылка на поле (результат), возвращаемое из конвейера агрегации, вам необходимо использовать переменную $$new
.
db.collection.aggregate([
{
$unwind: "$products"
},
{
$group: {
_id: {
order_id: "$order_id",
productName: "$products.name"
},
hasDefects: {
$push: "$products.hasDefect"
},
products: {
$push: "$products"
}
}
},
{
$set: {
hasDefect: {
$switch: {
branches: [
{
case: {
$allElementsTrue: {
$map: {
input: "$hasDefects",
as: "d",
in: {
$eq: [
"$$d",
"YES"
]
}
}
}
},
then: "YES"
},
{
case: {
$in: [
"NO",
"$hasDefects"
]
},
then: "NO"
},
{
case: {
$in: [
"NOT_SURE",
"$hasDefects"
]
},
then: "NOT_SURE"
}
],
default: "<DEFAULT>"
}
}
}
},
{
$group: {
_id: "$_id.order_id",
products: {
$push: {
name: "$_id.productName",
hasDefect: "$hasDefect"
}
}
}
},
{
$merge: {
into: "order",
whenMatched: [
{
$addFields: {
products: {
$let: {
vars: {
newProducts: "$$new.products"
},
in: {
$concatArrays: [
{
$map: {
input: "$products",
as: "oldProduct",
in: {
$cond: {
if: {
$in: [
"$$oldProduct.name",
"$$newProducts.name"
]
},
then: {
$first: {
$filter: {
input: "$$newProducts",
cond: {
$eq: [
"$$this.name",
"$$oldProduct.name"
]
}
}
}
},
else: "$$oldProduct"
}
}
}
},
{
$filter: {
input: "$$newProducts",
cond: {
$not: {
$in: [
"$$this.name",
"$products.name"
]
}
}
}
}
]
}
}
}
}
}
],
whenNotMatched: "insert"
}
}
])