Operators

The following is a list of the available update operators for the Mangrove expression builder. This page follows the structure of the MongoDB update operator documentation .

Field Update Operators

  • $inc

    The $inc operator is provided as the C++ += and -= operators. The unary ++ and -- can also be used. It is only enabled for fields with a numeric type.

    // Increment the age of users in the database.
    // The following three statements are the same, and produce the BSON:
    // { $inc: {age: 1}}
    auto res = User::update_many({}, MANGROVE_KEY(User::age) += 1);
    res = User::update_many({}, MANGROVE_KEY(User::age)++);
    res = User::update_many({}, ++MANGROVE_KEY(User::age));
    
    // Decrement the time left in the free trial of some product.
    // The following three statements are the same, and produce the BSON:
    // { $inc: {trial_days_left: -1}}
    auto res = User::update_many({}, MANGROVE_KEY(User::trial_days_left) -= 1);
    res = User::update_many({}, MANGROVE_KEY(User::trial_days_left)--);
    res = User::update_many({}, --MANGROVE_KEY(User::trial_days_left));
    
  • $mul

    The $mul operator is provided as the C++ *= operator. It is only enabled for fields with a numeric type.

    // Double the scores of users in a game.
    // { $mul: {score: 2}}
    auto res = User::update_many({}, MANGROVE_KEY(User::score) *= 2);
    
  • $rename

    Mangrove does not provide the $rename operator, since changing the name of fields created during serialization is not possible.

  • $setOnInsert

    This operator is provided as a member function on the fields. The given value must be the same type as the field (or implicitly cast to it).

    // Reset the score of a user, or create a new one.
    // Note the use of the "upsert" option, to enable insertion of a new document if necessary.
    // { $set: {score: 0}, $setOnInsert: {hours_played: 0} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     (MANGROVE_KEY(User::score) = 0,
                                      MANGROVE_KEY(User::hours_played).set_on_insert(0)),
                                     mongocxx::options::update{}.upsert(true));
    
  • $set

    The $set operator is provided as the C++ assignment operator =. The given value must be the same type as the field (or implicitly cast to it).

    // Edit the username of a user
    // { $set: {username: "brohemian_raphsody"}}
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                    MANGROVE_KEY(User::username) = "brohemian_raphsody");
    
  • $unset

    This operator is provided as a member function on fields that takes no arguments. The field it is used on must be an optional field. Otherwise, an error is raised at compile time.

    // Remove the "current_school" field from a user who has graduated:
    // {$unset: {current_school: ""}}
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::current_school).unset());
    
  • $min

    This operator is provided as a member function on fields. The given value must be the same type as the field (or implicitly cast to it).

    // Update a user's lowest score in a game.
    // {$min: {lowest_score: 45}}
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::lowest_score).min(45));
    
  • $max

    This operator is provided as a member function on fields. The given value must be the same type as the field (or implicitly cast to it).

    // Update a user's high score in a game.
    // {$max: {lowest_score: 1000}}
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::high_score).max(1000));
    
  • $currentDate

    To set a field to the current date using the $currentDate operator, one can use assign the reserved value mangrove::current_date to a field using =. This is only enabled for date or timestamp fields. The $type argument to the $currentDate operator is determined by the type of the field itself.

    // Update a user's "last played" date.
    // { $currentDate: {last_played: {$type: "date"}} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::last_played) = mangrove::current_date);
    

Array Update Operators

  • $

    The $ operator is used to update the first element in an array that matches the given query. This is done in Mangrove by using the .first_match() member function on name-value-pairs. The result is then used in an update expression as if it were a regular name-value pair.

    This operator is only enabled for fields that are arrays.

    // Double a players' first score over 1000.
    // { $mul: {"scores.$": 2}}
    auto res = User::update_many(MANGROVE_KEY(User::scores).elem_match(MANGROVE_ELEM(User::scores) > 1000),
                                      MANGROVE_KEY(User::scores).first_match() *= 2);
    
  • $addToSet

    This operator is available as a member function on the fields objects. It is only enabled for fields that are arrays. There are two versions: one that takes a single value to be added to the array, and another that takes an iterable containing multiple values to be added. The second one is equivalent to using the $each modifier with $addToSet.

    // Add a movie to a user's set of purchased movies.
    // { $addToSet: {purchased_movies: "The Matrix"} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                      MANGROVE_KEY(User::purchased_movies).add_to_set("The Matrix"));
    // Add several movies at once:
    // { $addToSet: {purchased_movies:
    //                  {$each: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"]}
    //              } }
    auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
    res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                 MANGROVE_KEY(User::purchased_movies).add_to_set(movies));
    
  • $pop

    This operator is provided as a member function on the name-value-pairs. It accepts a single parameter, a boolean last that determines whether an element should be removed from the end (if last == true) of the list, or the start (if last == false).

    // Remove the earliest score of some user.
    // { $pop: {scores: -1} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                MANGROVE_KEY(User::scores).pop(false));
    
  • $pull

    This operator is provided as a member function on the name-value-pairs. There are two options: one which takes a value to be removed from the list, and another which takes a query and removes values that match the given query.

    In the second one, the syntax for queries is similar to that of the $elemMatch operators. One can use find queries as they would at the top level (i.e. when passing to find(...)), except that scalar arrays need to use the MANGROVE_ELEM macro to refer to elements.

    $pull is only enabled for fields that are arrays.

    // Remove the first matrix movie from a user's purchased movies.
    // { $pull: {purchased_movies: "The Matrix"} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                      MANGROVE_KEY(User::purchased_movies).pull("The Matrix"));
    
    // Remove any and all matrix movies from a user's purchased movies.
    // { $pull: {purchased_movies: {$regex: "matrix", $options: "i"}} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::purchased_movies).pull(MANGROVE_ELEM(User::purchased_movies)).regex("matrix", "i"));
    
  • $pullAll

    This operator is provided as a member function on the fields. It accepts an iterable argument, that contains a list of values to remove from the field’s array. This operator is only enabled for fields that are arrays.

    // Remove the three matrix movies from a user's purchased movies.
    // { $pullAll: {purchased_movies: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"]} }
    auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::purchased_movies).pullAll(movies));
    
  • $pushAll

    $pushAll is deprecated, one should use $push instead.

  • $push

    The $push operator is provided as a member function on the fields. There are two versions: one which takes a single value to push onto the array, and another which takes an iterable, and pushes all the values onto the array using the $each modifier.

    This operator is only enabled for fields that are arrays.

    // Push a single movie to a user's watched_movies field:
    // {$push: {watched_movies: "The Matrix"}}
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::watched_movies).push("The Matrix"));
    
    // This user watched every Matrix movie in one sitting:
    // {$push: {watched_movies: {$each: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"]}}}
    auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
    res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                MANGROVE_KEY(User::watched_movies).push(movies));
    

    As per the MongoDB documentation, $push can accept several optional modifiers. Modifiers to this operator can either be specified as optional arguments to the function, or using a “fluent” API. This means that parameters are given as .push(values).slice(...).sort(...).position(...).

    • $slice — this modifier takes a 32-bit integer that limits the number of array elements.

      // Add movies to this user's history, but limit its length to 10.
      // {
      //  $push: {
      //      watched_movies: {$each: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"],
      //                       $slice: 10}
      //      }
      // }
      auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
      res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                  MANGROVE_KEY(User::watched_movies).push(movies).slice(10));
      
    • $sort — this modifier takes either an integer that is ±1, or a sort expression. An integer argument will sort values by their natural ordering, either in ascending (+1) or descending (-1) order. A sort expression represents an ordering based on a specific field. It can be specified by calling the .sort(bool ascending) function on a name-value pair. The boolean argument ascending orders elements in ascending order if true, or descending if false.

      // Add movies to this user's history, then sort movies in ascending order by their title.
      // {
      //  $push: {
      //      watched_movies: {$each: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"],
      //                       $sort: 1}
      //      }
      // }
      auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
      res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                  MANGROVE_KEY(User::watched_movies).push(movies).sort(1));
      

      If, in the above example, movies were not strings but documents, with a title and rating field, one would be able to choose how to sort them as follows:

      // Add movies to this user's history, then sort movies by rating in descending order.
      // {
      //  $push: {
      //      watched_movies: {$each: [ {title: "The Matrix", rating: 9},
      //                                {title: "The Matrix: Reloaded", rating: 7},
      //                                {title: "The Matrix: Revolutions", rating: 3} ],
      //                       $sort: {rating: -1}}
      //      }
      // }
      
      // brace-initialize "Movie" objects.
      auto movies = std::vector<Movie>{{"The Matrix", 9}, {"The Matrix: Reloaded", 7},
                                             {"The Matrix: Revolutions", 3}};
      res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                  MANGROVE_KEY(User::watched_movies).push(movies).sort(MANGROVE_KEY(Movie::rating).sort(false)));
      
    • $position — this modifier takes an unsigned integer that represents a position in the array.

      // Add movies to this user's history, but add them at the start (i.e. 0th position)
      // of the array.
      // {
      //  $push: {
      //      watched_movies: {$each: ["The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"],
      //                       $position: 0}
      //      }
      // }
      auto movies = std::vector<std::string>{"The Matrix", "The Matrix: Reloaded", "The Matrix: Revolutions"};
      res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                  MANGROVE_KEY(User::watched_movies).push(movies).position(0));
      

Bitwise Operators

  • $bit

    Bitwise updates on fields can be performed using C++’s built-in &=, |=, and ^= operators. These are only enabled for integer fields.

    // Perform bitwise operations on a user's age, because, hey, why not?!
    // { $bit: {age: {and: 7}} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                     MANGROVE_KEY(User::age) &= 7);
    
    // { $bit: {age: {or: 7}} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                      MANGROVE_KEY(User::age) |= 7);
    
    // { $bit: {age: {xor: 7}} }
    auto res = User::update_one(MANGROVE_KEY(User::username) == "raphofkhan",
                                       MANGROVE_KEY(User::age) ^= 7);
    

Isolation Operators

  • $isolated

    An update expression can be marked as isolated using the $isolated operator. In Mangrove, is this done by passing the query expression used to match documents to the mangrove::isolated function.

    // Set the 'can_buy_alcohol' flag for all users over the age of 21, but isolate the updates
    // to avoid concurrency issues. This is equivalent to the mongo shell command:
    // db.testcollection.updateMany({age: {$gt: 21}, $isolated: 1},
    //                          {$set: {can_buy_alcohol: true}})
    auto res = User::update_many(mangrove::isolated(MANGROVE_KEY(User::age) >= 21),
                                     MANGROVE_KEY(User::can_buy_alcohol) = true);