// It's possible to use $reduce to handle the "insert a document // immediately after (or before) a matching document" use case: db.marching_order.updateOne( { _id : 'column-one' }, [ { $set : { marchers : { $reduce : { input : '$marchers', initialValue : [], in : { // iterate through the marchers list (an array of documents with // a name property), and apply the rules in this $switch to each // matching person that we find... $switch : { // Within the `$reduce`, the `$$this` variable refers to the // current element of the list, and the `$$value` variable is // the accumulator.. For JavaScript devs it's something like: // $marchers.reduce( ( $$value, $$this ) => {} ); branches : [ { // When we find "Bob"... case : { $eq : [ "$$this.name", "Bob" ] }, // we want to add "Alice" right before him then : { $concatArrays : [ // Note that the accumulator is already an array // (because of the `initialValue : []` up at the // beginning)... "$$value", // But for other values we need to wrap them in an // array. [ { name : "Alice", age : 11 } ], [ "$$this" ], ] }, }, { // When we find "Chuck"... case : { $eq : [ "$$this.name", "Chuck" ] }, // we're going to add 4 people behind him then : { $concatArrays : [ "$$value", [ "$$this", { name : "Dave", age : 20 }, { name : "Dave Too", age : 19 }, { name : "Also Dave", age : 17 }, { name : "Elwood", age : 43 }, ] ] }, }, { // We're also going to remove everyone from the list who // is bad at marching case : { $or : [ // Zeke is terrible at marching { $eq : [ "$$this.name", "Zeke" ] }, // Everyone under 3 just gets in the way { $lt : [ "$$this.age", 3 ] }, // Everyone over 100 ends up needing a wheelchair { $gt : [ "$$this.age", 100 ] }, ] }, // Returning the accumulator without adding "$$this" to it // effectively removes that item from the list. then : "$$value", }, ], // The default if none of the branches matched is to just add // that item the accumulator. default : { $concatArrays : [ "$$value", [ "$$this" ] ] }, }, }, } } } } ] );