How to find 3rd depth selector in Recoil? - reactjs

I am making web pages through Next.js and Recoil.
I'm making global data for the problem through recoil, but I don't know how to get the value in the 3rd depth.
export const surveyState = atom<ISurveyData>({
key: "surveyState",
default: {
id: 0,
subject: "",
content: "",
startDate: "",
endDate: "",
minute: 0,
openFl: 1,
tempFl: 1,
closingComment: "",
hashtag: [],
sections: [
{
title: "",
content: "",
nextSection: -1,
questions: [ //I want to get the number of this attribute.
{
ask: "",
explain: "",
multiFl: 1,
essFl: 0,
dupFl: 0,
oder: 0,
questionItems: [{ content: "", oder: 0, nextSection: 0 }],
},
],
},
],
},
});
//I want to import it as a selector like this.
export const partCountState = selector({
key: "partCount",
get: ({ get }) => {
const survey = get(surveyState);
return survey.sections.length;
},
});
I want to get the length of the questions in each section.
Each index of the sections can have different lengths of qusetions, how can I get them into a selector?
This is intended to show the total number of problems.

Related

Flattening folders

I've been having a problem trying to flatten the folders in this format:
for example we have this folder structure. The names should be changed as on the right side, whether as the format of each folder should be flattened.
The goal is for the folders to be flattened and each of their names should be for example:
If A has a subfolder B and subfolder C, C's name should be: A/B/C, B's name should be A/B.
{
id: "0",
name: null,
parentId: null,
folderType: "chatMessages",
folders: [
{
id: 3195588631115178,
name: "Testfolder",
parentId: null,
folderType: "chatMessages",
folders: [
{
id: "3195588620182363",
name: "Subfolder",
parentId: "3195588631115178",
folderType: "chatMessages",
folders: [
{
id: "3206824598737435",
name: "Interesting",
parentId: "3195588620182363",
folderType: "chat",
folders: [],
items: [
{
id: "3208409930553392",
name: "Message",
folderId: "3206824598737435",
updated: "2022-05-27T07:28:40.450Z",
frontendFolderId: null,
text: "<p>This is an HTML with Image.</p>",
keywords: "test",
subject: "What kind of subject",
slashCommand: "test",
language: "en-US",
setupItemId: "3208409930553392",
},
],
},
],
items: [
{
id: "3195595211854821",
name: "Message in subfolder",
folderId: "3195588620182363",
updated: "2022-05-19T12:05:39.503Z",
frontendFolderId: null,
text: "Message in subfolder",
keywords: "test",
subject: "Message in subfolder",
slashCommand: "sub",
language: "bn-BD",
setupItemId: "3195595211854821",
},
],
},
],
items: [],
},
],
items: [
{
id: "2888102250465731",
name: "bye",
folderId: null,
updated: "2022-05-25T11:15:36.367Z",
frontendFolderId: null,
text: "Thanks for contacting us. Please do not hesitate to contact us again if we can be of further assistance.",
keywords: "bye",
subject: null,
slashCommand: null,
language: null,
setupItemId: "2888102250465731",
},
],
}
UPDATE: How can I create an array of every item and their id, folderId and text properties?
I want to achieve this format:
{
id: "3195595211854821",
folderId: "3195588620182363",
text: "Message in subfolder",
}
Maybe something like this gets you started? Here flat is a recursive generator that yields array paths of name attributes -
function *flat({ name = "", folders = [], items = [] }) {
yield [name]
for (const x of [...folders, ...items])
for (const path of flat(x))
yield [name, ...path]
}
for (const path of flat(data))
console.log(path.join("/"))
/Testfolder
/Testfolder/Subfolder
/Testfolder/Subfolder/Interesting
/Testfolder/Subfolder/Interesting/Message
/Testfolder/Subfolder/Message in subfolder
/bye
Run the snippet below to verify the result in your own browser -
const data = {id:"0",name:null,parentId:null,folderType:"chatMessages",folders:[{id:3195588631115178,name:"Testfolder",parentId:null,folderType:"chatMessages",folders:[{id:"3195588620182363",name:"Subfolder",parentId:"3195588631115178",folderType:"chatMessages",folders:[{id:"3206824598737435",name:"Interesting",parentId:"3195588620182363",folderType:"chat",folders:[],items:[{id:"3208409930553392",name:"Message",folderId:"3206824598737435",updated:"2022-05-27T07:28:40.450Z",frontendFolderId:null,text:"<p>This is an HTML with Image.</p>",keywords:"test",subject:"What kind of subject",slashCommand:"test",language:"en-US",setupItemId:"3208409930553392",},],},],items:[{id:"3195595211854821",name:"Message in subfolder",folderId:"3195588620182363",updated:"2022-05-19T12:05:39.503Z",frontendFolderId:null,text:"Message in subfolder",keywords:"test",subject:"Message in subfolder",slashCommand:"sub",language:"bn-BD",setupItemId:"3195595211854821",},],},],items:[],},],items:[{id:"2888102250465731",name:"bye",folderId:null,updated:"2022-05-25T11:15:36.367Z",frontendFolderId:null,text:"Thanks for contacting us. Please do not hesitate to contact us again if we can be of further assistance.",keywords:"bye",subject:null,slashCommand:null,language:null,setupItemId:"2888102250465731",},],}
function *flat({ name = "", folders = [], items = [] }) {
yield [name]
for (const x of [...folders, ...items])
for (const path of flat(x))
yield [name, ...path]
}
for (const path of flat(data))
console.log(path.join("/"))
.as-console-wrapper { min-height: 100%; top: 0; }
Here's a second option that builds a path of nodes objects, not just the name properties. This gives the caller the option to use any node properties when constructing the output path -
function *flat(t = {}) {
yield [t]
for (const x of [...t.folders ?? [], ...t.items ?? []])
for (const path of flat(x))
yield [t, ...path]
}
for (const path of flat(data))
console.log(
path.map(node => `${node.name ?? ""}<#${node.id}>`).join("/")
)
<#0>
<#0>/Testfolder<#3195588631115178>
<#0>/Testfolder<#3195588631115178>/Subfolder<#3195588620182363>
<#0>/Testfolder<#3195588631115178>/Subfolder<#3195588620182363>/Interesting<#3206824598737435>
<#0>/Testfolder<#3195588631115178>/Subfolder<#3195588620182363>/Interesting<#3206824598737435>/Message<#3208409930553392>
<#0>/Testfolder<#3195588631115178>/Subfolder<#3195588620182363>/Message in subfolder<#3195595211854821>
<#0>/bye<#2888102250465731>
Run the snippet below to verify the result in your own browser -
const data = {id:"0",name:null,parentId:null,folderType:"chatMessages",folders:[{id:3195588631115178,name:"Testfolder",parentId:null,folderType:"chatMessages",folders:[{id:"3195588620182363",name:"Subfolder",parentId:"3195588631115178",folderType:"chatMessages",folders:[{id:"3206824598737435",name:"Interesting",parentId:"3195588620182363",folderType:"chat",folders:[],items:[{id:"3208409930553392",name:"Message",folderId:"3206824598737435",updated:"2022-05-27T07:28:40.450Z",frontendFolderId:null,text:"<p>This is an HTML with Image.</p>",keywords:"test",subject:"What kind of subject",slashCommand:"test",language:"en-US",setupItemId:"3208409930553392",},],},],items:[{id:"3195595211854821",name:"Message in subfolder",folderId:"3195588620182363",updated:"2022-05-19T12:05:39.503Z",frontendFolderId:null,text:"Message in subfolder",keywords:"test",subject:"Message in subfolder",slashCommand:"sub",language:"bn-BD",setupItemId:"3195595211854821",},],},],items:[],},],items:[{id:"2888102250465731",name:"bye",folderId:null,updated:"2022-05-25T11:15:36.367Z",frontendFolderId:null,text:"Thanks for contacting us. Please do not hesitate to contact us again if we can be of further assistance.",keywords:"bye",subject:null,slashCommand:null,language:null,setupItemId:"2888102250465731",},],}
function *flat(t = {}) {
yield [t]
for (const x of [...t.folders ?? [], ...t.items ?? []])
for (const path of flat(x))
yield [t, ...path]
}
for (const path of flat(data))
console.log(
path.map(node => `${node.name ?? ""}<#${node.id}>`).join("/")
)
.as-console-wrapper { min-height: 100%; top: 0; }

Updating an array of objects in react redux

The initial state looks like:
const state = {
profile: [
{
form: {
name: "",
surname: "",
born_date: "",
phone_number: 0,
city: "",
title: "",
},
experience: [],
training: [],
languages: [],
abilities: [],
},
],
}
I just want to remove an object of experience array, and return the new array to state and refresh view without this item, but it doesn't work as expected, don't know how can i set the new array in experience: []
i tried some posibilities.
if (state.profile[0].experience.length > 1) {
let experiences = [...state.profile[0].experience];
let newExp = experiences.slice(0, action.payload).concat(experiences.slice(action.payload + 1)); //Slice works
experiences = { ...experiences, experience: newExp };
return {
...state,
profile: [...state.profile,[{ experience: newExp}]]
};
}
thx!

Typescript merging 2 arrays and increase qty if they have the same id

I'm doing with my Angular 8 project and I want to merge 2 arrays into 1 and increase qty if they have the same value in the object. I have tried a few times by myself and it does not really work well.
mergedOrderList: any[]= [];
lstOldOrder: any[] = [
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},];
lstNewOrder: any[] = [
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},
{id: "", products_id: "", qty: 1, ...},];
lstNewOrder.forEach(newOrder => {
let isDubplicated: boolean = false;
lstOldOrder.forEach(oldOrder => {
if (newOrder.products_id == oldOrder.products_id) {
oldOrder.qty += newOrder.qty;
isDubplicated = true;
mergedOrderList.push(oldOrder);
}
});
if (!isDubplicated) {
mergedOrderList.push(newOrder)
}
});
I did like this and they work when they both have the same products_id. But when new order doesn't have products_id. They skip my old order and add only new order to the list. I'm not quite sure I'm done it right. Thanks
See the problem is that you are only adding data from lstOldOrder in mergedOrderList if the
product_id of new list item matches with any item in old list.
So you are not able to see any item from old list if all the items are new in lstNewOrder
Instead what you should do is :
Add the item to the mergedOrderList but increase the quantity if there is a match.
mergedOrderList = [];
lstOldOrder = [
{ id: "1", products_id: "", qty: 1 },
{ id: "2", products_id: "", qty: 1 },
{ id: "3", products_id: "", qty: 1 },
];
lstNewOrder = [
{ id: "4", products_id: "", qty: 1 },
{ id: "5", products_id: "", qty: 1 },
{ id: "1", products_id: "", qty: 1 },
];
lstNewOrder.forEach((newOrder) => {
Oindex = -1;
lstOldOrder.forEach((item, index) => {
if (item.id == newOrder.id) {
Oindex = index; // Getting the Index of that item in old array.
}
});
if (Oindex != -1) { // if that item was in old Array
newOrder.qty += lstOldOrder[Oindex].qty; // Increase Quantity in newOrderItem
lstOldOrder.splice(Oindex, 1); // Delete that Item from OldArray
}
mergedOrderList.push(newOrder); // Add the Item in Merged
});
mergedOrderList.concat(lstOldOrder); // Finally add all the remaining Items
All the edge cases in the code are not handled properly sorry for that.
Feel free to edit my answer, it may help someone else

How to retrieve value of key from an object inside an array

I'm trying to retrieve the merchant name from within the following array:
[
{
"model": "inventory.merchant",
"pk": 1,
"fields": {
"merchant_name": "Gadgets R Us",
"joined": "2020-01-06T07:16:17.365Z"
}
},
{"model": "inventory.merchant", "pk": 2, "fields": {"merchant_name": "H&M", "joined": "2020-01-07T22:21:52Z"}},
{"model": "inventory.merchant", "pk": 3, "fields": {"merchant_name": "Next", "joined": "2020-01-07T22:22:56Z"}},
{"model": "inventory.merchant", "pk": 4, "fields": {"merchant_name": "Jill Fashion", "joined": "2020-01-07T22:26:48Z"}}
]
I'm using vuejs and have used axios to fetch the above data via an api. I put in an array called merchants[]. I'm able to get any item I want from within my html using v-for i.e.
<div v-for="merchant in merchants">
<p>{{ merchant.fields.merchant_name }}</p>
</div>
However, in my .js file, doing the following does not work:
console.log(this.merchants[0].fields.merchant_name)
I get the following error in my console:
vue.js:634 [Vue warn]: Error in render: "TypeError: Cannot read property 'fields' of undefined"
Please help
Edit:
This is my .js file. I try to log the merchants name in the console from the merchantName() computed property:
new Vue({
delimiters: ['[[', ']]'],
el: "#inventory",
data: {
gallery: true,
inCart: false,
shipping: false,
galleryView: "zoom",
ref: "",
cart: [],
isSelected: false,
selectedClass: "in_cart",
shippingCost: 2000,
inventory: [],
merchants: [],
},
methods: {
zoomGallery(){
this.galleryView = "zoom"
},
back(){
this.gallery = "thumbnail"
},
addToCart(name, merchant, price, qty, image, id){
var itemClone = {}
itemClone = {
"merchant": merchant,
"name": name,
"price": price,
"qty": qty,
"image": "/media/" + image,
"id": id,
}
this.cart.push(itemClone)
this.isSelected = true
},
removeFromCart(index){
this.cart.splice(index, 1)
},
deleteFromCart(id){
console.log(id)
// right now, any caret down button deletes any input
// I need to use components to prevent that
if (this.cart.length > 0){
index = this.cart.findIndex(x => x.id === id)
this.cart.splice(index, 1)
}
},
viewCart(){
this.gallery = false
this.shipping = false
this.inCart = true
},
viewShipping(){
this.gallery = false
this.shipping = true
this.inCart = false
}
},
computed: {
itemsInCart(){
return this.cart.length
},
subTotal(){
subTotal = 0
inCart = this.cart.length
for (i=0; i<inCart; i++) {
subTotal += Number(this.cart[i].price)
}
return subTotal
},
checkoutTotal(){
return this.subTotal + this.shippingCost
},
merchantName(){
console.log(this.merchants[0])
},
},
beforeMount() {
axios
.get("http://127.0.0.1:8000/get_products/").then(response => {
(this.inventory = response.data)
return axios.get("http://127.0.0.1:8000/get_merchants/")
})
.then(response => {
(this.merchants = response.data)
})
},
});
Edit:
Response from console.log(this.merchants) is:
[__ob__: Observer]
length: 0
__ob__: Observer
value: Array(0)
length: 0
__ob__: Observer {value: Array(0), dep: Dep, vmCount: 0}
__proto__: Array
dep: Dep
id: 16
subs: Array(0)
length: 0
__proto__: Array(0)
__proto__: Object
vmCount: 0
__proto__:
walk: ƒ walk(obj)
observeArray: ƒ observeArray(items)
constructor: ƒ Observer(value)
__proto__: Object
__proto__: Array
Why you are trying to console.log this.merchants in computed property. Check for computed property of vuejs here.
Your data is empty before data from API call even come. So that's why your this.merchants is empty.
You can get you this.merchants value by using a method and run it after your api call or watching that like this:
watch: {
merchants: function () {
console.log(this.merchants)
}
}
It will console this.merchants array everytime a change happens in it.

Update nested subdocuments in MongoDB with arrayFilters

I need to modify a document inside an array that is inside another array.
I know MongoDB doesn't support multiple '$' to iterate on multiple arrays at the same time, but they introduced arrayFilters for that.
See: https://jira.mongodb.org/browse/SERVER-831
MongoDB's sample code:
db.coll.update({}, {$set: {“a.$[i].c.$[j].d”: 2}}, {arrayFilters: [{“i.b”: 0}, {“j.d”: 0}]})
Input: {a: [{b: 0, c: [{d: 0}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Output: {a: [{b: 0, c: [{d: 2}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Here's how the documents are set:
{
"_id" : ObjectId("5a05a8b7e0ce3444f8ec5bd7"),
"name" : "support",
"contactTypes" : {
"nonWorkingHours" : [],
"workingHours" : []
},
"workingDays" : [],
"people" : [
{
"enabled" : true,
"level" : "1",
"name" : "Someone",
"_id" : ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
"contacts" : [
{
"_id" : ObjectId("5a05a8dee0ce3444f8ec5bda"),
"retries" : "1",
"priority" : "1",
"type" : "email",
"data" : "some.email#email.com"
}
]
}
],
"__v" : 0
}
Here's the schema:
const ContactSchema = new Schema({
data: String,
type: String,
priority: String,
retries: String
});
const PersonSchema = new Schema({
name: String,
level: String,
priority: String,
enabled: Boolean,
contacts: [ContactSchema]
});
const GroupSchema = new Schema({
name: String,
people: [PersonSchema],
workingHours: { start: String, end: String },
workingDays: [Number],
contactTypes: { workingHours: [String], nonWorkingHours: [String] }
});
I need to update a contact. This is what I tried using arrayFilters:
Group.update(
{},
{'$set': {'people.$[i].contacts.$[j].data': 'new data'}},
{arrayFilters: [
{'i._id': mongoose.Types.ObjectId(req.params.personId)},
{'j._id': mongoose.Types.ObjectId(req.params.contactId)}]},
function(err, doc) {
if (err) {
res.status(500).send(err);
}
res.send(doc);
}
);
The document is never updated and I get this response:
{
"ok": 0,
"n": 0,
"nModified": 0
}
What am I doing wrong?
So the arrayFilters option with positional filtered $[<identifier>] does actually work properly with the development release series since MongoDB 3.5.12 and also in the current release candidates for the MongoDB 3.6 series, where this will actually be officially released. The only problem is of course is that the "drivers" in use have not actually caught up to this yet.
Re-iterating the same content I have already placed on Updating a Nested Array with MongoDB:
NOTE Somewhat ironically, since this is specified in the "options" argument for .update() and like methods, the syntax is generally compatible with all recent release driver versions.
However this is not true of the mongo shell, since the way the method is implemented there ( "ironically for backward compatibility" ) the arrayFilters argument is not recognized and removed by an internal method that parses the options in order to deliver "backward compatibility" with prior MongoDB server versions and a "legacy" .update() API call syntax.
So if you want to use the command in the mongo shell or other "shell based" products ( notably Robo 3T ) you need a latest version from either the development branch or production release as of 3.6 or greater.
All this means is that the current "driver" implementation of .update() actually "removes" the necessary arguments with the definition of arrayFilters. For NodeJS this will be addressed in the 3.x release series of the driver, and of course "mongoose" will then likely take some time after that release to implement it's own dependencies on the updated driver, which would then no longer "strip" such actions.
You can however still run this on a supported server instance, by dropping back to the basic "update command" syntax usage, since this bypassed the implemented driver method:
const mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = mongoose.Types.ObjectId;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const contactSchema = new Schema({
data: String,
type: String,
priority: String,
retries: String
});
const personSchema = new Schema({
name: String,
level: String,
priority: String,
enabled: Boolean,
contacts: [contactSchema]
});
const groupSchema = new Schema({
name: String,
people: [personSchema],
workingHours: { start: String, end: String },
workingDays: { type: [Number], default: undefined },
contactTypes: {
workingHours: { type: [String], default: undefined },
contactTypes: { type: [String], default: undefined }
}
});
const Group = mongoose.model('Group', groupSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clean data
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.remove() )
);
// Create sample
await Group.create({
name: "support",
people: [
{
"_id": ObjectId("5a05a8c3e0ce3444f8ec5bd8"),
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "adifferent.email#example.com"
},
{
"_id": ObjectId("5a05a8dee0ce3444f8ec5bda"),
"retries": "1",
"priority": "1",
"type": "email",
"data": "some.email#example.com"
}
]
}
]
});
let result = await conn.db.command({
"update": Group.collection.name,
"updates": [
{
"q": {},
"u": { "$set": { "people.$[i].contacts.$[j].data": "new data" } },
"multi": true,
"arrayFilters": [
{ "i._id": ObjectId("5a05a8c3e0ce3444f8ec5bd8") },
{ "j._id": ObjectId("5a05a8dee0ce3444f8ec5bda") }
]
}
]
});
log(result);
let group = await Group.findOne();
log(group);
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})()
Since that sends the "command" directly through to the server, we see the expected update does in fact take place:
Mongoose: groups.remove({}, {})
Mongoose: groups.insert({ name: 'support', _id: ObjectId("5a06557fb568aa0ad793c5e4"), people: [ { _id: ObjectId("5a05a8c3e0ce3444f8ec5bd8"), enabled: true, level: '1', name: 'Someone', contacts: [ { type: 'email', data: 'adifferent.email#example.com', _id: ObjectId("5a06557fb568aa0ad793c5e5") }, { _id: ObjectId("5a05a8dee0ce3444f8ec5bda"), retries: '1', priority: '1', type: 'email', data: 'some.email#example.com' } ] } ], __v: 0 })
{ n: 1,
nModified: 1,
opTime:
{ ts: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
t: 24 },
electionId: 7fffffff0000000000000018,
ok: 1,
operationTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
'$clusterTime':
{ clusterTime: Timestamp { _bsontype: 'Timestamp', low_: 3, high_: 1510364543 },
signature: { hash: [Object], keyId: 0 } } }
Mongoose: groups.findOne({}, { fields: {} })
{
"_id": "5a06557fb568aa0ad793c5e4",
"name": "support",
"__v": 0,
"people": [
{
"_id": "5a05a8c3e0ce3444f8ec5bd8",
"enabled": true,
"level": "1",
"name": "Someone",
"contacts": [
{
"type": "email",
"data": "adifferent.email#example.com",
"_id": "5a06557fb568aa0ad793c5e5"
},
{
"_id": "5a05a8dee0ce3444f8ec5bda",
"retries": "1",
"priority": "1",
"type": "email",
"data": "new data" // <-- updated here
}
]
}
]
}
So right "now"[1] the drivers available "off the shelf" don't actually implement .update() or it's other implementing counterparts in a way that is compatible with actually passing through the necessary arrayFilters argument. So if you are "playing with" a development series or release candiate server, then you really should be prepared to be working with the "bleeding edge" and unreleased drivers as well.
But you can actually do this as demonstrated in any driver, in the correct form where the command being issued is not going to be altered.
[1] As of writing on November 11th 2017 there is no "official" release of MongoDB or the supported drivers that actually implement this. Production usage should be based on official releases of the server and supported drivers only.
I had a similar use case. But my second level nested array doesn't have a key. While most examples out there showcase an example with arrays having a key like this:
{
"id": 1,
"items": [
{
"name": "Product 1",
"colors": ["yellow", "blue", "black"]
}
]
}
My use case is like this, without the key:
{
"colors": [
["yellow"],
["blue"],
["black"]
]
}
I managed to use the arrayfilters by ommiting the label of the first level of the array nest. Example document:
db.createCollection('ProductFlow')
db.ProductFlow.insertOne(
{
"steps": [
[
{
"actionType": "dispatch",
"payload": {
"vehicle": {
"name": "Livestock Truck",
"type": "road",
"thirdParty": true
}
}
},
{
"actionType": "dispatch",
"payload": {
"vehicle": {
"name": "Airplane",
"type": "air",
"thirdParty": true
}
}
}
],
[
{
"actionType": "store",
"payload": {
"company": "Company A",
"is_supplier": false
}
}
],
[
{
"actionType": "sell",
"payload": {
"reseller": "Company B",
"is_supplier": false
}
}
]
]
}
)
In my case, I want to:
Find all documents that have any steps with payload.vehicle.thirdParty=true and actionType=dispatch
Update the actions set payload.vehicle.thirdParty=true only for the actions that have actionType=dispatch.
My first approach was withour arrayfilters. But it would create the property payload.vehicle.thirdParty=true inside the steps with actionType store and sell.
The final query that updated the properties only inside the steps with actionType=dispatch:
Mongo Shell:
db.ProductFlow.updateMany(
{"steps": {"$elemMatch": {"$elemMatch": {"payload.vehicle.thirdParty": true, "actionType": "dispatch"}}}},
{"$set": {"steps.$[].$[i].payload.vehicle.thirdParty": false}},
{"arrayFilters": [ { "i.actionType": "dispatch" } ], multi: true}
)
PyMongo:
query = {
"steps": {"$elemMatch": {"$elemMatch": {"payload.vehicle.thirdParty": True, "actionType": "dispatch"}}}
}
update_statement = {
"$set": {
"steps.$[].$[i].payload.vehicle.thirdParty": False
}
}
array_filters = [
{ "i.actionType": "dispatch" }
]
NOTE that I'm omitting the label on the first array at the update statement steps.$[].$[i].payload.vehicle.thirdParty. Most examples out there will use both labels because their objects have a key for the array. I took me some time to figure that out.

Resources