1

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?

Vermouth
  • 21
  • 2

3 Answers3

1

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"]

Octo Poulos
  • 523
  • 6
  • 5
0

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")))))))
);
SPM
  • 405
  • 1
  • 5
  • 16
0

If you want to push new elements without tampering the existing array of strings,try the following code segment:

 bsoncxx::builder::basic::document update_builder;
    
/*Define the update to be performed on the document*/

bsoncxx::builder::basic::array new_array;
new_array.append("T1");
new_array.append("T2");
new_array.append("T3");
update_builder.append(kvp("$set", make_document(kvp("field_name", new_array))));
          
auto updating = update_builder.extract();
    
/*Update the document*/
auto result = m_dbCollection.update_one(filter.view(), updating.view());

For clearing the existing elements in the field and update it with new array of strings,you may try the following

/*Clear the existing data in the field*/

bsoncxx::builder::basic::document update_builder;
update_builder.append(kvp("$set",make_document(kvp("field_name", bsoncxx::types::b_array{}))));
auto update = update_builder.extract();
    
/*Define the update to be performed on the document*/

bsoncxx::builder::basic::array new_array;
new_array.append("T1");
new_array.append("T2");
new_array.append("T3");
update_builder.append(kvp("$set", make_document(kvp("field_name", new_array))));
          
auto updating = update_builder.extract();
    
/*Update the document*/
auto result = m_dbCollection.update_one(filter.view(), updating.view());
Raj Mohan
  • 316
  • 2
  • 5