MongoDB more Update

Insert many
  • Send multiple data in one request will be faster than insert one by one
  • Command line tool mongoimport can be used to import data instead of insertMany many times
  • Message size can’t be larger than 48 MB
> db.movies.insertMany([{"title":"Movie 1"},{"title":"Movie 2"},{"title":"Movie 3"}])
{
    "acknowledged" : true,
    "insertedIds" : [
        ObjectId("5f6876732fbc27989eb7f4c2"),
        ObjectId("5f6876732fbc27989eb7f4c3"),
        ObjectId("5f6876732fbc27989eb7f4c4")
    ]
}

Ordered and unordered insert
Ordered insert (Default): MongoDB stop insert later records whenever any data insert fail
Unordered insert: MongoDB will try to insert all data regardless some data fail, unordered insert will have better performance

drop 
ex. db.movies.drop()
> db.movies.insertOne(movie2)
{
        "acknowledged" : true,
        "insertedId" : ObjectId("5f68e75e85d32460c3bfa6e3")
}
> db.movies.find().pretty()
{
        "_id" : ObjectId("5f68e75885d32460c3bfa6e2"),
        "title" : "A movie",
        "director" : "A director",
        "year" : 2020
}
{
        "_id" : ObjectId("5f68e75e85d32460c3bfa6e3"),
        "title" : "A movie 2",
        "director" : "A director 2",
        "year" : 2020
}
> db.movies.drop()
true
> db.movies.find().pretty()

update
It seems update is an atomic operation, but I'm curious what will happen when two update operations happen at the same time, and the second operation filter criteria is not matched because the first operation modified the data?
> db.movies.find().pretty()
{
        "_id" : ObjectId("5f6950a694d2d7702605f470"),
        "title" : "A movie",
        "director" : "A director",
        "year" : 2020
}
{
        "_id" : ObjectId("5f6950a794d2d7702605f471"),
        "title" : "A movie 2",
        "director" : "A director 2",
        "year" : 2020
}

// Update one movie
> db.movies.updateOne({"title":"A movie"},{$set:{"year":2021,"review":0}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.movies.find({"title":"A movie"}).pretty()
{
        "_id" : ObjectId("5f6950a694d2d7702605f470"),
        "title" : "A movie",
        "director" : "A director",
        "year" : 2021,
        "review" : 0
}

replace
replace command will replace whole document
> db.movies.replaceOne({"title":"A movie"}, {"title":"B movie", "year":1990})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.movies.find().pretty()
{
        "_id" : ObjectId("5f6950a694d2d7702605f470"),
        "title" : "B movie",
        "year" : 1990
}
{
        "_id" : ObjectId("5f6950a794d2d7702605f471"),
        "title" : "A movie 2",
        "director" : "A director 2",
        "year" : 2020
}

increment a number
// create page document
> pageA= {"page":"page A", "view":0}
{ "page" : "page A", "view" : 0 }
> db.page.insertOne(pageA)
{
        "acknowledged" : true,
        "insertedId" : ObjectId("5f69551d94d2d7702605f472")
}

// check data
> db.page.find({"page":"page A"}).pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "view" : 0
}

// increment
> db.page.updateOne({"page":"page A"},{"$inc":{"view":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// check result
> db.page.find({"page":"page A"}).pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "view" : 1
}

$unset
// check there is a view property
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "view" : 1
}

// unset view property
> db.page.updateOne({"page":"page A"},{"$unset":{"view":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// check view property disappeared
> db.page.find().pretty()
{ "_id" : ObjectId("5f69551d94d2d7702605f472"), "page" : "page A" }

$set change attribute value in embedded document
// set new property: user
> db.page.updateOne({"page":"page A"}, {"$set":{
...    "user":{
...      "display_name":"",
...      "devices":[
...
...      ],
...      "subscriptions":{
...          "vpn":{
...            "active":true,
...          }
...      },
...      "max_devices":5
...    },
... }})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// check data
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "user" : {
                "display_name" : "",
                "devices" : [ ],
                "subscriptions" : {
                        "vpn" : {
                                "active" : true
                        }
                },
                "max_devices" : 5
        }
}

// change display_name
> db.page.updateOne({"page":"page A"},{"$set":{"user.display_name":"ABCDE"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// check update result
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "user" : {
                "display_name" : "ABCDE",
                "devices" : [ ],
                "subscriptions" : {
                        "vpn" : {
                                "active" : true
                        }
                },
                "max_devices" : 5
        }
}

$push data to array attribute
// push data to array attribute
> db.page.updateOne({"page":"page A"},{"$push":{"comment":"hello"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.page.updateOne({"page":"page A"},{"$push":{"comment":"hello2"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// check result
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "comment" : [
                "hello",
                "hello2"
        ]
}

$push multiple elements to an array attribute by $each
// Can't add multiple elements to an array by simply $push
> db.page.updateOne({"page":"page A"},{"$push":{"comment":["hello3","hello4"]}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// Because only $push will add only one element, thus one element with array value will be added
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "comment" : [
                "hello",
                "hello2",
                [
                        "hello3",
                        "hello4"
                ]
        ]
}

// Need $each to add multiple elements
> db.page.updateOne({"page":"page A"},{"$push":{"comment":{"$each":["hello3","hello4"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "comment" : [
                "hello",
                "hello2",
                [
                        "hello3",
                        "hello4"
                ],
                "hello3",
                "hello4"
        ]
}

$slice array to 3 elements when performing $each
> db.page.updateOne({"page":"page A"},{"$push":{"comment":{"$each":[],"$slice":-3}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

// rest 3 records
> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "comment" : [
                [
                        "hello3",
                        "hello4"
                ],
                "hello3",
                "hello4"
        ]
}


$sort when $slice
> db.page.updateOne({"page":"page A"},{"$push":{"top3":{"$each":[{"name":"A","height":5},{"name":"B","height":4},{"name":"C","height":3},{"name":"D","height":2},{"name":"E","height":1}],"$slice":-3,"$sort":{"height":1}}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.page.find().pretty()
{
        "_id" : ObjectId("5f69551d94d2d7702605f472"),
        "page" : "page A",
        "comment" : [
                "hello3",
                "hello4"
        ],
        "top3" : [
                {
                        "name" : "C",
                        "height" : 3
                },
                {
                        "name" : "B",
                        "height" : 4
                },
                {
                        "name" : "A",
                        "height" : 5
                }
        ]
}

$push comment
> db.users.updateOne({"name":"user1"},{"$push":{"comment":{"email":"a@gmail.com"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.updateOne({"name":"user1"},{"$push":{"comment":{"email":"b@gmail.com"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.find().pretty()
{
        "_id" : ObjectId("5f6a38748074fb4051b75cb8"),
        "name" : "user1",
        "comment" : [
                {
                        "email" : "a@gmail.com"
                },
                {
                        "email" : "b@gmail.com"
                }
        ]
}

$push and then $addToSet phone with $each
> user = {"name":"user 1"}
{ "name" : "user 1" }
> db.users.insertOne(user)
{
    "acknowledged" : true,
    "insertedId" : ObjectId("5f6c46393c90a681c72b7df5")
}

> db.users.updateOne({"name":"user 1"},{$push:{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "123456"
    ]
}

// add existing phone, no modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "123456"}})
{ "acknowledged" : true, “matchedCount" : 1, "modifiedCount" : 0 }

// add new phone
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "123456",
        "223456"
    ]
}

// add existing phone, no modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": "223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }

// add multiple elements by $each, one non-existing phone, so one modification
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "123456",
        "223456",
        "12345"
    ]
}


Remove element by $pop, $pop 1 remove from end, $pop -1 remove from beginning
> db.users.updateOne({"name":"user 1"}, {"$pop":{"phone": 1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "123456",
        "223456"
    ]
}

> db.users.updateOne({"name":"user 1"}, {"$pop":{"phone": -1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456"
    ]
}

Remove element by $pull
// pull element but value is not matched, no modification
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }

//
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"223456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [ ]
}

Remove multiple elements by $pull
// push elements
> db.users.updateOne({"name":"user 1"}, {"$addToSet":{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "123456"
    ]
}
> db.users.updateOne({"name":"user 1"}, {$push:{"phone": {"$each":["223456","12345","123456"]}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "123456",
        "223456",
        "12345",
        "123456"
    ]
}

// pull 123456, all 123456 will be removed
> db.users.updateOne({"name":"user 1"}, {"$pull":{"phone":"123456"}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ]
}

$inc increase value in specified index array
// original data
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ]
}

// push 2 comments
> db.users.updateOne({"name":"user 1"}, {$push:{"comment":{"vote":0,"message":"haha"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.updateOne({"name":"user 1"}, {$push:{"comment":{"vote":0,"message":"haha 2"}}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 0,
            "message" : "haha"
        },
        {
            "vote" : 0,
            "message" : "haha 2"
        }
    ]
}

// increase the first element vote
> db.users.updateOne({"name":"user 1"}, {"$inc":{"comment.0.vote":1}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "haha"
        },
        {
            "vote" : 0,
            "message" : "haha 2"
        }
    ]
}

// increase 100 to the second element
> db.users.updateOne({"name":"user 1"}, {"$inc":{"comment.1.vote":100}})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "haha"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ]
}

// update message when array element match arrayFilters
> db.users.updateOne({"name":"user 1"}, {$set:{"comment.$[elmt].message":"Good"}},{arrayFilters:[{"elmt.vote":{$lte: 11}}]})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "Good"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ]
}

upsert: update when exist, otherwise, insert
// upsert age to user 1
> db.users.updateOne({"name":"user 1"},{"$set":{"age":10}},{"upsert":true})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "Good"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ],
    "age" : 10
}

// upsert age to user 2
> db.users.updateOne({"name":"user 2"},{"$set":{"age":10}},{"upsert":true})
{
    "acknowledged" : true,
    "matchedCount" : 0,
    "modifiedCount" : 0,
    "upsertedId" : ObjectId("5f6d6fa0d8c8c1bae1785718")
}
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "Good"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ],
    "age" : 10
}
{
    "_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
    "name" : "user 2",
    "age" : 10
}

$setOnInsert to config attribute when insert
// set createdAt when insert
> db.users.updateOne({"name":"user 2"},{"$setOnInsert":{"createdAt":new Date()}},{"upsert":true})
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "Good"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ],
    "age" : 10
}
{
    "_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
    "name" : "user 2",
    "age" : 10
}

// 
> db.users.updateOne({"name":"user 3"},{"$setOnInsert":{"createdAt":new Date()}},{"upsert":true})
{
    "acknowledged" : true,
    "matchedCount" : 0,
    "modifiedCount" : 0,
    "upsertedId" : ObjectId("5f6d738ed8c8c1bae1785730")
}
> db.users.find().pretty()
{
    "_id" : ObjectId("5f6c46393c90a681c72b7df5"),
    "name" : "user 1",
    "phone" : [
        "223456",
        "12345",
        "223456",
        "12345"
    ],
    "comment" : [
        {
            "vote" : 1,
            "message" : "Good"
        },
        {
            "vote" : 100,
            "message" : "haha 2"
        }
    ],
    "age" : 10
}
{
    "_id" : ObjectId("5f6d6fa0d8c8c1bae1785718"),
    "name" : "user 2",
    "age" : 10
}
{
    "_id" : ObjectId("5f6d738ed8c8c1bae1785730"),
    "name" : "user 3",
    "createdAt" : ISODate("2020-09-25T04:35:26.398Z")
}

findOneAndUpdate can handle race condition, but it return old document by default. 
Can returnNewDocument to return the one after modification
// update and return old document
> db.users.findOneAndUpdate({"name":"user1"},{"$push":{"phone":{"$each":["123456"]}}})
{
        "_id" : ObjectId("5f6a38748074fb4051b75cb8"),
        "name" : "user1",
        "comment" : [
                {
                        "email" : "a@gmail.com"
                },
                {
                        "email" : "b@gmail.com"
                }
        ]
}

// update and return new document
> db.users.findOneAndUpdate({"name":"user1"},{"$push":{"phone":{"$each":["1234567"]}}},{"returnNewDocument":true})
{
        "_id" : ObjectId("5f6a38748074fb4051b75cb8"),
        "name" : "user1",
        "comment" : [
                {
                        "email" : "a@gmail.com"
                },
                {
                        "email" : "b@gmail.com"
                }
        ],
        "phone" : [
                "123456",
                "1234567"
        ]
}




沒有留言:

張貼留言

別名演算法 Alias Method

 題目 每個伺服器支援不同的 TPM (transaction per minute) 當 request 來的時候, 系統需要馬上根據 TPM 的能力隨機找到一個適合的 server. 雖然稱為 "隨機", 但還是需要有 TPM 作為權重. 解法 別名演算法...