1. 程式人生 > >MongoDB修改器和pymongo

MongoDB修改器和pymongo

MongoDB修改器

在mongodb中通常文件只會有一部分要更新,利用原子的更新修改器,可以做到只更新文件的一部分鍵值,而且更新極為高效,更新修改器是種特殊的鍵,用來指定複雜的更新操作,比如調整、增加、或者刪除鍵,還可以運算元組和內嵌文件。增加、修改或刪除鍵的時候,應該使用$修改器

1. $set修改器

  $set修改器用來指定一個鍵值. 如果這個鍵不存在, 則建立它,它對於更新模式或者使用者定義鍵來說很方便.

> db.users.findOne()
{
        "_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
        
"name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : "war and pace" } > db.users.update({"name":"joe"},{"$set":{"favorite book":["cat's cardle","foundation trilogy","ender's game"]}}) WriteResult({ "nMatched" : 1, "nUpserted
" : 0, "nModified" : 1 }) > db.users.findOne() { "_id" : ObjectId("56fe7df8b322e3ff1dabf834"), "name" : "joe", "age" : 30, "sex" : "male", "location" : "Wisconsin", "favorite book" : [ "cat's cardle", "foundation trilogy
", "ender's game" ] }

2. $set用來修改內嵌文件

> db.blog.insert({"title":"a blog post","author":{"name":"joe","email":"[email protected]"}})
WriteResult({ "nInserted" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "author" : {
                "name" : "joe",
                "email" : "[email protected]"
        }
}
> db.blog.update({"author.name":"joe"},{"$set":{"author.name":"joe schmoe"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "author" : {
                "name" : "joe schmoe",
                "email" : "[email protected]"
        }
}
> db.blog.update({"title":"a blog post"},{"$set":{"author.name":"joe schmoe op"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "author" : {
                "name" : "joe schmoe op",
                "email" : "[email protected]"
        }
}

3. $unset修改器

  $unset修改用於將鍵刪除

> db.users.findOne()
{
        "_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
        "name" : "joe",
        "age" : 30,
        "sex" : "male",
        "location" : "Wisconsin",
        "favorite book" : [
                "cat's cardle",
                "foundation trilogy",
                "ender's game"
        ]
}
> db.users.update({"name":"joe"},{"$unset":{"favorite book":1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("56fe7df8b322e3ff1dabf834"),
        "name" : "joe",
        "age" : 30,
        "sex" : "male",
        "location" : "Wisconsin"
}

4. $inc修改器

  $inc其用來增加或減少已有的鍵的鍵值,或者在鍵不存在的時候建立一個鍵。

> db.games.insert({"game":"pinball","user":"joe"})
WriteResult({ "nInserted" : 1 })
> db.games.findOne()
{
        "_id" : ObjectId("5770a1394f533aa7535d46d4"),
        "game" : "pinball",
        "user" : "joe"
}
> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
        "_id" : ObjectId("5770a1394f533aa7535d46d4"),
        "game" : "pinball",
        "user" : "joe",
        "score" : 50
}

  為"score"鍵增加50再減少20

> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
        "_id" : ObjectId("5770a1394f533aa7535d46d4"),
        "game" : "pinball",
        "user" : "joe",
        "score" : 100
}
> db.games.update({"game":"pinball","user":"joe"},{"$inc":{"score":-20}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.games.findOne()
{
        "_id" : ObjectId("5770a1394f533aa7535d46d4"),
        "game" : "pinball",
        "user" : "joe",
        "score" : 80
}

  以上"$inc"與"$set"的用法類似,就是專門用來增加或減少數字的。"$inc"只能用於整數、長整數或雙精度浮點數,要是在其他型別的資料上就會導致操作失敗,其中包括很多語言會自動轉換成數字的型別,例如null,布林型別,或數字構成的字串。"$inc"鍵的值必須為數字,不能使用字串、陣列和其他非數字的值,否則會報錯,要修改其他型別,只能使用"$set"。

> db.foo.insert({"count":"1"})
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5770befc4f533aa7535d46d5"), "count" : "1" }
> db.foo.update({},{"$inc":{"count":1}})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 0,
        "nModified" : 0,
        "writeError" : {
                "code" : 16837,
                "errmsg" : "Cannot apply $inc to a value of non-numeric type. {_id: ObjectId('5770befc4f533aa7535d46d5')} has the field 'count' of non-numeric type String"
        }
})

> db.foo.update({},{$set:{count:2}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : ObjectId("5770befc4f533aa7535d46d5"), "count" : 2 }
>

5. 陣列修改器 $push

  陣列修改器,顧名思義它只可以用於運算元組,只能用在值為陣列的鍵上。$push修改器如果指定的值已經存在,"$push"會想已有的陣列末尾加入一個元素,要是沒有就會建立一個新的陣列

> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "author" : {
                "name" : "joe schmoe op",
                "email" : "[email protected]"
        }
}
> db.blog.update({"title":"a blog post"},{"$unset":{"author":1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{ "_id" : ObjectId("57709da84f533aa7535d46d3"), "title" : "a blog post" }
> db.blog.update({"title":"a blog post"},{"$push":{"comments":{"name":"joe","email":"[email protected]","content":"nice post"}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                }
        ]
}

6. 陣列修改器 $ne

  $ne也是用來運算元組的修改器,在查詢文件中,如果一個值不在數組裡面就把他加進去,如果在不新增

> db.users.insert({"name":"joe","emails":["[email protected]","[email protected]","[email protected]"]})
WriteResult({ "nInserted" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"name":"joe","emails":{$ne:"[email protected]"}},{$push:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })                                    --nMatched為0表示沒有修改
> db.users.update({"name":"joe","emails":{$ne:"[email protected]"}},{$push:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}

  以上這種方式也可以使用$addToSet實現。

7. 陣列修改器 $addToSet

  $addToSet也是用來運算元組的修改器,實現的功能與$ne修改器相同,且更為方便。使用$addToSet修改器可以避免重複

> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]om",
                "[email protected]"
        ]
}
> db.users.update({"_id":ObjectId("5770ca42e90c1adc80040a08")},{$addToSet:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })     --原文件裡已有"[email protected]",修改完也沒有產生重複值
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"_id":ObjectId("5770ca42e90c1adc80040a08")},{$addToSet:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}

8. 陣列修改器 $each

  $each陣列修改器要和$addToSet修改結合起來用,可以一次新增多個不同的值。例如上面的例子中,我們一次新增多個email值, 如下:

> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"_id":ObjectId("5770ca42e90c1adc80040a08")},{$addToSet:{$each:["[email protected]","[email protected]","[email protected]"]}})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 0,
        "nModified" : 0,
        "writeError" : {
                "code" : 52,
                "errmsg" : "The dollar ($) prefixed field '$each' in '$each' is not valid for storage."
        }
})
> db.users.update({"_id":ObjectId("5770ca42e90c1adc80040a08")},{$addToSet:{"emails":{$each:["[email protected]","[email protected]","[email protected]"]}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}

9. 陣列修改器 $pop

  $pop修改器主要於從陣列中刪除元素,他可以從陣列中的任何一端刪除元素,
例如:
  {$pop:{key:1}} 從陣列末尾刪除一個元素
  {$pop:{key:-1}} 從陣列頭部刪除一個元素

> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"name":"joe"},{$pop:{"emails":1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"name":"joe"},{$pop:{"emails":-1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}

  有時我們需要基於特定條件來刪除元素,而不僅僅依據位置,就可以使用$pull修改器

10. 陣列修改器 $pull

  $pull修改器和$pop修改類似,都是用來刪除陣列中的元素
  $pull可以基於特定條件來刪除元素
  $pull會將所有匹配到的資料全部刪掉,如對陣列[1,2,1,1]執行pull 1,得到的結果就是隻有一個元素的陣列[2]

  例如我們想刪除emails陣列中的"[email protected]"和"[email protected]"兩個元素:

> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"name":"joe"},{$pull:{"emails":["[email protected]","[email protected]"]}})   
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })  --好像不能一次刪除多個,沒有起作用
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}
> db.users.update({"name":"joe"},{$pull:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.update({"name":"joe"},{$pull:{"emails":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.users.findOne()
{
        "_id" : ObjectId("5770ca42e90c1adc80040a08"),
        "name" : "joe",
        "emails" : [
                "[email protected]",
                "[email protected]",
                "[email protected]"
        ]
}

11. 陣列的定位修改器 $

  若是陣列有多個值,而我們只想對其中一部分進行操作,有兩種方法可以實現這種操作。
  兩種方法運算元組中的值:通過位置或定位操作符("$")

  陣列都是以0開頭的,可以將下標直接作為鍵來選擇元素。

> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                },
                {
                        "name" : "bob",
                        "email" : "[email protected]",
                        "content" : "good post"
                }
        ]
}
> db.blog.update({"title":"a blog post"},{$set:{"comments.1.name":"livan"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                },
                {
                        "name" : "livan",
                        "email" : "[email protected]",
                        "content" : "good post"
                }
        ]
}
> db.blog.update({"title":"a blog post"},{$set:{"comments.1.email":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                },
                {
                        "name" : "livan",
                        "email" : "[email protected]",
                        "content" : "good post"
                }
        ]
}

  在很多情況下,不預先查詢文件就不能知道要修改陣列的下標,為了克服這種困難,mongodb提供了定位操作符"$",
  用來定位查詢文件已經匹配的元素,並進行更新,定位符只更新第一個匹配的元素。
  例如:使用者john把名字改成了jim,就可以用定位符來替換評論中的名字:
  db.blog.update({"comments.author":"john"},{$set:{"comments.$.author:"john"}})
  可以理解為{"comments.author":"john"}查詢條件定位到第一個元素,就執行{$set:      {"comments.$.author:"john"}},"$"定位符就表示找到的第一個元素

> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                },
                {
                        "name" : "livan",
                        "email" : "[email protected]",
                        "content" : "good post"
                }
        ]
}
> db.blog.update({"comments.name":"livan"},{$set:{"comments.$.email":"[email protected]"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.update({"comments.name":"livan"},{$set:{"comments.$.name":"bob"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.blog.findOne()
{
        "_id" : ObjectId("57709da84f533aa7535d46d3"),
        "title" : "a blog post",
        "comments" : [
                {
                        "name" : "joe",
                        "email" : "[email protected]",
                        "content" : "nice post"
                },
                {
                        "name" : "bob",
                        "email" : "[email protected]",
                        "content" : "good post"
                }
        ]
}