My document example:
{
id: 139234234,
count: 12,
type: apple,
buyer: [
{name: "peter", price: 1.23, max: 129},
{name: "alex", price: 1.4, "max": 12146}
]
}
My update:
db.updateMany({ id: 139234234 }, [
{
$set: {
buyer: {
$concatArrays: [
{
$filter: {
input: "$buyer",
cond: {
{ $ne: ["$$this.name", "john"] },
},
},
},
[
{
name: "john",
price: 12,
max: 234,
},
],
],
},
},
},
]);
I frequently do this kind of update in buyer
field, what should I write for the change stream pipeline (db.collection.watch(changeStreamPipeline)
) if I want any update not include buyer
.
For example:
The current update description
updateDescription: {
updatedFields: {
'buyer.2.name': "alex",
'buyer.2.price': 1.4,
'buyer.2.max': 12146,
}}
I don't want to receive any message of the updateFields
that start with buyer
, for exmaple: buyer.2.name
, buyer.2.price
.
I tried the following pipeline, but it only works for the update field that exactly is buyer
:
db.collection.watch(
[
{
$match: {
operationType: "update",
"updateDescription.updatedFields.buyer": {
$exists: false
}
}
}
]
)
What you can do is add an $addFields
stage prior to your $match
stage, in which we'll remove all "buyer" keys from the object before performing the match stage to see if any other fields were updated,
Here is how I did this using $objectToArray
and $regexMatch
:
const pipeline = [
{
$addFields: {
"updateDescription.updatedFields": {
$arrayToObject: {
$filter: {
input: {
$objectToArray: { $ifNull: ["$updateDescription.updatedFields", {}]}
},
cond: {
$not: { $regexMatch: {input: "$$this.k", regex: /^buyer\..*/,} }
}
}
}
}
}
},
{
$match: {
$or: [
{
operationType: {$in: ["update", 'replace']},
$expr: {
$gt: [
{$size: {$objectToArray: { $ifNull: ["$updateDescription.updatedFields", {}]}}},
0
]
}
},
{
operationType: {$in: ["delete", 'insert']},
}
]
}
}
];
const changeStream = collection.watch(pipeline);