void User::IncrCredits(const std::string& section, long long kBytes) { auto doIncrement = [section, kBytes](acl::UserID uid) { NoErrorConnection conn; auto updateExisting = [&]() -> bool { auto query = BSON("uid" << uid << "credits" << BSON("$elemMatch" << BSON("section" << section))); auto update = BSON("$inc" << BSON("credits.$.value" << kBytes)); auto cmd = BSON("findandmodify" << "users" << "query" << query << "update" << update); mongo::BSONObj result; return conn.RunCommand(cmd, result) && result["value"].type() != mongo::jstNULL; }; auto doInsert = [&]() -> bool { auto query = QUERY("uid" << uid << "credits" << BSON("$not" << BSON("$elemMatch" << BSON("section" << section)))); auto update = BSON("$push" << BSON("credits" << BSON("section" << section << "value" << kBytes))); return conn.Update("users", query, update, false) > 0; }; if (updateExisting()) return; if (doInsert()) return; if (updateExisting()) return; logs::Database("Unable to increment credits for UID %1%%2%", uid, !section.empty() ? " in section " + section : std::string("")); }; asyncTasks.Assign(std::async(std::launch::async, doIncrement, user.id)); }