'Mongocxx - Update an array within a document?

I have a document in MongoDB with the following structure:

{
"_id":"$oid":"621fbaeaeedd1c000e60fbd2"},
"username":"myuser",
"password":"mypassword",
"comments":["comment1", "comment2", "comment3"]
}

I have a vector of comments:

std::vector<std::string> mycomments; 
mycomments.push_back("comment2"); 
mycomments.push_back("comment4");

I would like to insert, if it is not already present, each string of the vector "mycomments" into the array "comments" in MongoDB document. I read MongoDB documentation, but I did not understand how to use the function "update_one", as in the documentation there is only a very simple case. So the solution that I adopted is the following: I get the content of comments and I put it into a vector, I push each string of mycomments into this vector (if it is not already present), then I delete the document in MongoDB and I insert a new document with new values:

bsoncxx::stdx::optional<bsoncxx::document::value> res = collection.find_one(document{} << "username" << username << finalize);
    if (res)
    {
        coll.delete_one(document{} << "username" << username << finalize);

        document data_builder{};
        data_builder << "username" << username << "password" << password;
        auto array_builder = data_builder << "comments" << open_array;
        for (std::string str : myNewVector)
        {
            array_builder << str;
        }
        array_builder << close_array;
        bsoncxx::document::view_or_value doc = data_builder << finalize;
        coll.insert_one(doc);

    }

Clearly this is a very foolish solution, since it would be enough to use the update_one function, but from the documentation I cannot understand how to use it (in this complex case). Can you help me please?



Solution 1:[1]

One way to add multiple strings to an array without duplicates is with the $addToSet operator and the $each modifier:

coll.update_one(
  make_document( kvp("username", "myuser") ), // filter part

  make_document(                              // update part
    kvp("$addToSet",
        make_document( kvp("comments",
                           make_document( kvp("$each",
                                              make_array("comment2", "comment4")))))))
);

Solution 2:[2]

If you want to keep the order, then you must get the document and only push the comments that are not already present in it.

Then, you can use the $push and $each modifier. Here's the reference: https://docs.mongodb.com/manual/reference/operator/update/push/#append-multiple-values-to-an-array

I ran this code:

    std::vector<std::string> mycomments;
    mycomments.push_back("comment2");
    mycomments.push_back("comment4");

    auto eachDoc = document{};
    auto arrayDoc = eachDoc << "$each" << open_array;
    for (auto& comment : mycomments)
        arrayDoc << comment;
    arrayDoc << close_array;

    auto findDoc = document{} << "username" << "myuser" << finalize;
    auto update = document{} << "$push" << open_document << "comments" << eachDoc << close_document << finalize;

    collection.update_one(findDoc.view(), update.view());

And I obtained: ["comment1", "comment2", "comment3", "comment2", "comment4"]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SPM
Solution 2