Search code examples
javascriptmongodbspring-bootaggregation-frameworkspring-data-mongodb

Convert following MongoDB update statement to SpringBoot equivalent


I am trying to remove an element from a list inside a document using the index as suggested here

db.example.update({}, [
     {$set:{ sequence: {
           $concatArrays:[ 
               {$slice:[ "$sequence", P ]}, 
               {$slice:[ "$sequence", {$add:[1,P]}, {$size:"$sequence"}]}
           ]
     }}}
]);

However, I am having problems while trying to convert the query to the spring syntax equivalent:

Update update = new Update();

/*how do I pass the slice in the following statement?*/
ArrayOperators.ConcatArrays array = ArrayOperators.ConcatArrays.arrayOf(****);
SetOperators.SetUnion setUnion = SetOperators.SetUnion.arrayAsSet(** slice with add and size***).union(array);
update.set("sequence", setUnion);

Thanks


Solution

  • The second parameter to $concatArrays should look something like this.

    ArrayOperators.Slice.sliceArrayOf("sequence")
    .offset(P+1)
    .itemCount(ArrayOperators.Size.lengthOfArray("sequence"));
    

    Unfortunately, itemCount accepts only int arguments, so this won't work.

    If your array has distinct elements, you can try this modified query.

    db.collection.update({},
    [
      {
        "$set": {
          "sequence": {
            "$concatArrays": [
              {
                "$slice": ["$sequence",P]
              },
              {
                "$setDifference": [
                  "$sequence",
                  {
                    "$slice": ["$sequence",{$add:[P,1]}]
                  }
                ]
              }
            ]
          }
        }
      }
    ])
    

    Demo

    Since you need pipelined update, you need to use AggregationUpdate.

    AggregationUpdate update = Aggregation.newUpdate()
        .set("sequence")
        .toValue(ArrayOperators.ConcatArrays
            .arrayOf(ArrayOperators.Slice.sliceArrayOf("sequence").itemCount(P))
            .concat(SetOperators.SetDifference.arrayAsSet("sequence")
                .differenceTo(ArrayOperators.Slice.sliceArrayOf("sequence").itemCount(P+1))));
            
    

    Another easier way is to do this in javascript using $function

    db.collection.update({},[
    {
        $set: {
            "sequence": {
                $function: {
                    body: function(sequence) {
                        sequence.splice(P,1);
                        return sequence;
                    },
                    args: ["$sequence"],
                    lang: "js"
                }
            }
        }
    }
    ]);
    

    Demo

    AggregationUpdate update = Aggregation.newUpdate()
        .set("sequence")
        .toValue(ScriptOperators
            .function("function(sequence) {\r\n" 
                + "  sequence.splice(P,1);\r\n"
                + "  return sequence;\r\n" 
                + "}")
            .args("$sequence")
            .lang("js"));