zoukankan      html  css  js  c++  java
  • MongoDB学习笔记三—增删改文档上

    插入insert

    单条插入

    > db.foo.insert({"bar":"baz"})
    WriteResult({ "nInserted" : 1 })

    批量插入

    > db.foo.insert([{"_id":1},{"_id":2},{"_id":3}])
    BulkWriteResult({
            "writeErrors" : [ ],
            "writeConcernErrors" : [ ],
            "nInserted" : 3,
            "nUpserted" : 0,
            "nMatched" : 0,
            "nModified" : 0,
            "nRemoved" : 0,
            "upserted" : [ ]
    })
    > db.foo.find()
    { "_id" : 1 }
    { "_id" : 2 }
    { "_id" : 3 }
    > 

    如果在执行批量插入的过程中有一个文档插入失败,那么在这个文档之前的所有文档都会插入成功,之后的所有全部失败。

    > db.foo.insert([{"_id":10},{"_id":11},{"_id":10},{"_id":12}])
    BulkWriteResult({
            "writeErrors" : [
                    {
                            "index" : 2,
                            "code" : 11000,
                            "errmsg" : "E11000 duplicate key error collection: test.foo index: _id_ dup key: { : 10.0 }",
                            "op" : {
                                    "_id" : 10
                            }
                    }
            ],
            "writeConcernErrors" : [ ],
            "nInserted" : 2,
            "nUpserted" : 0,
            "nMatched" : 0,
            "nModified" : 0,
            "nRemoved" : 0,
            "upserted" : [ ]
    })
    > db.foo.find()
    { "_id" : 10 }
    { "_id" : 11 }
    > 

    删除文档

    remove

    remove函数接受一个查询文档作为参数。符合条件的文档才被删除。删除数据是永久性的,不能撤销,也不能恢复。

    > db.foo.remove()
    2016-12-15T19:50:31.721+0800 E QUERY    [thread1] Error: remove needs a query :
    DBCollection.prototype._parseRemove@src/mongo/shell/collection.js:406:1
    DBCollection.prototype.remove@src/mongo/shell/collection.js:433:18
    @(shell):1:1
    
    > db.foo.remove({"_id":10})
    WriteResult({ "nRemoved" : 1 })
    > db.foo.find()
    { "_id" : 11 }
    > 

    drop

    要清空整个集合,那么使用drop直接删除集合会更快。代价是:不能指定任何限定条件。整个集合都被删除,所有元数据都不见了。

    > for(var i=0;i<1000000;i++){
    ... db.tester.insert({"foo":"bar","baz":i,"z":10-i})
    ... }
    WriteResult({ "nInserted" : 1 })
    > db.tester.find()
    { "_id" : ObjectId("58528543b049609a5fa74f7c"), "foo" : "bar", "baz" : 0, "z" : 10 }
    ......
    Type "it" for more > db.tester.drop()//插入一百万条数据,使用drop删除,只需1ms true >

    更新文档update

    Update有两个必须参数:

    一是查询文档,用于定位需要更新的目标文档

    二是修改器文档,用于说明要找到的文档进行哪些修改

    更新操作是不可分割的:若是两个更新同时发生,先到达服务器的先执行,接着执行另一个。

    db.foo.insert({
    ... "name":"yyb",
    ... "friends":32,
    ... "enemies":2
    ... })
    WriteResult({ "nInserted" : 1 })
    > db.foo.update({"name":"yyb"},{"name":"joe"})//将yyb这个文档修改成{“name”:“joe”}
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.foo.find()
    { "_id" : ObjectId("58528a2bb049609a5fb691bc"), "name" : "joe" }
    > 

    文档替换

    用一个新文档完全替换匹配的文档,这适合大规模模式迁移的情况。

      db.user.insert({
    ... ... "name":"joe",
    ... ... "friends":32,
    ... ... "enemies":2
    ... ... })
    WriteResult({ "nInserted" : 1 })
    //将上面这个文档的后两个字段移到子文档为realtionships中
    > var joe=db.user.findOne({"name":"joe"})
    > joe.relationships={"friends":joe.friends,"enemies":joe.enemies};
    { "friends" : 32, "enemies" : 2 }
    > delete joe.friends
    true
    > delete joe.enemies
    true
    > db.user.update({"name":"joe"},joe);
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("58529188b049609a5fb691bf"), "name" : "joe", "relationships" : { "friends" : 32, "enemies" : 2 } }
    > 

    常见的错误是查询条件匹配到了多个文档,然后更新时由于第二个参数的存在就产生重复的 _id 值。数据库会抛出异常。

    > db.user.find()
    { "_id" : ObjectId("585295e3b049609a5fb691c5"), "name" : "yyb", "age" : 21 }
    { "_id" : ObjectId("585295e3b049609a5fb691c6"), "name" : "yyb", "age" : 30 }
    { "_id" : ObjectId("585295e3b049609a5fb691c7"), "name" : "yyb", "age" : 40 }
    > joe=db.user.findOne({"name":"yyb","age":30})
    { "_id" : ObjectId("585295e3b049609a5fb691c6"), "name" : "yyb", "age" : 30 }
    > joe.age++;
    30
    > db.user.update({"name":"yyb"},joe)
    WriteResult({
            "nMatched" : 0,
            "nUpserted" : 0,
            "nModified" : 0,
            "writeError" : {
                    "code" : 16837,
                    "errmsg" : "The _id field cannot be changed from {_id: ObjectId('585295e3b049609a5fb691c5')} to {_id: ObjectId('585295e3b049609a5fb691c6')}."
            }
    })
    > 

    使用修改器

    使用原子性的更新修改器,指定对文档的某些字段进行更新。更新修改器是种特殊的键,用来指定复杂的更新操作,比如修改、添加或者删除键,还可能是操作数组或者内嵌文档。

    > db.user.find()
    { "_id" : ObjectId("585295e3b049609a5fb691c5"), "name" : "yyb", "age" : 21 }
    { "_id" : ObjectId("585295e3b049609a5fb691c6"), "name" : "yyb", "age" : 30 }
    { "_id" : ObjectId("585295e3b049609a5fb691c7"), "name" : "yyb", "age" : 40 }
    > db.user.update({"name":"yyb"},{$inc:{"age":5}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })> db.user.find({"name":"yyb"})
    { "_id" : ObjectId("585295e3b049609a5fb691c5"), "name" : "yyb", "age" : 26 }
    { "_id" : ObjectId("585295e3b049609a5fb691c6"), "name" : "yyb", "age" : 30 }
    { "_id" : ObjectId("585295e3b049609a5fb691c7"), "name" : "yyb", "age" : 40 }
    > 

    明明匹配3条,却只改了一条。原来MongoDB默认只会更新匹配的第一条,如果要更新多条,还得指定参数。

    使用修改器时,_id的值不能改变。(整个文档替换时可以改变“_id”)

    $set与$unset

    用来指定一个字段的值。如果这个字段不存在,则创建它。

    > db.user.insert({
    ... "name":"yyb",
    ... "age":20,
    ... "sex":"male",
    ... "location":"cd"})
    WriteResult({ "nInserted" : 1 })
    >> db.user.update({"name":"yyb"},{"$set":{"email":"123@qq.com"}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find().pretty()
    {
            "_id" : ObjectId("58529e66b049609a5fb691c9"),
            "name" : "yyb",
            "age" : 20,
            "sex" : "male",
            "location" : "cd",
            "email" : "123@qq.com"
    }
    > 

    用 $set 甚至可以修改键的类型。用 $unset 可以将键完全删除。

    >  db.user.update(
    ... ... {"name":"yyb"},
    ... ... {"$set":{"email":["xx@qq.com","xl@sina.com"]}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find().pretty()
    {
            "_id" : ObjectId("58529e66b049609a5fb691c9"),
            "name" : "yyb",
            "age" : 20,
            "sex" : "male",
            "location" : "cd",
            "email" : [
                    "xx@qq.com",
                    "xl@sina.com"
            ]
    }
    > db.user.update({"name":"yyb"},{"$unset":{"email":1}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find().pretty()
    {
            "_id" : ObjectId("58529e66b049609a5fb691c9"),
            "name" : "yyb",
            "age" : 20,
            "sex" : "male",
            "location" : "cd"
    }

    也可以用 $set 修改内嵌文档:

    {
            "_id" : ObjectId("5853e17ff7720722b4ded850"),
            "title" : "a blog post",
            "content" : "...",
            "author" : {
                    "name" : "yyb",
                    "email" : "aaa@sina.com"
            }
    }
    > db.blog.update(
    ... {"author.name":"yyb"},
    ... {"$set":{"author.name":"joe"}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blog.findOne()
    {
            "_id" : ObjectId("5853e17ff7720722b4ded850"),
            "title" : "a blog post",
            "content" : "...",
            "author" : {
                    "name" : "joe",
                    "email" : "aaa@sina.com"
            }
    }

    增加、删除、修改键时,应该使用$开头的修改器,否则可能会将整个文档替换掉。

    $inc

     $inc 用来增加已有键的值,或者该键不存在那就创建一个。对于更新分析数据、因果关系、投票或者其他有变化数值的地方很方便。

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

     $inc 就是专门用来增减数字的。且只能用于整型、长整型或者双精度浮点型的值。其他类型的数据会操作失败。

    > db.foo.insert({"count":"1"})
    WriteResult({ "nInserted" : 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('5853e73df7720722b4ded853')} has the field 'count' of non-numeric type String"
            }
    })
    > 

     $inc 键的值必须为数字,不能使用字符串、数组或者其他非数字的值。要修改其他类型,应该使用 $set 或者数字修改器。

    > db.foo.insert({"count":1})
    WriteResult({ "nInserted" : 1 })
    
    > db.foo.update({},{"$inc":{"count":"5"}})
    WriteResult({
            "nMatched" : 0,
            "nUpserted" : 0,
            "nModified" : 0,
            "writeError" : {
                    "code" : 14,
                    "errmsg" : "Cannot increment with non-numeric argument: {count: "5"}"
            }
    })
    > 

    数组修改器

    $push

    $push 添加元素。如果数组已经存在,会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。

    > db.blog.post.findOne()
    {
            "_id" : ObjectId("5853ea01f7720722b4ded855"),
            "title" : "a blog post",
            "content" : "..."
    }
    > db.blog.post.update(
    ... {"title":"a blog post"},
    ... {"$push":{"comments":{"name":"joe","email":"joe@qq.com","content":"nice post"}}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blog.post.findOne()
    {
            "_id" : ObjectId("5853ea01f7720722b4ded855"),
            "title" : "a blog post",
            "content" : "...",
            "comments" : [
                    {
                            "name" : "joe",
                            "email" : "joe@qq.com",
                            "content" : "nice post"
                    }
            ]
    }
    > 
    > db.blog.post.update(
    ... {"title":"a blog post"},
    ... {"$push":{"comments":{"name":"bob","email":"bob@sina.com","content":"good post."}}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blog.post.findOne()
    {
            "_id" : ObjectId("5853ea01f7720722b4ded855"),
            "title" : "a blog post",
            "content" : "...",
            "comments" : [
                    {
                            "name" : "joe",
                            "email" : "joe@qq.com",
                            "content" : "nice post"
                    },
                    {
                            "name" : "bob",
                            "email" : "bob@sina.com",
                            "content" : "good post."
                    }
            ]
    }
    > 

    $each

    可以将它应用在一些比较复杂的数组操作中。使用 $each 子操作符,可以通过一次 $push 操作添加多个值。

    比如:下面将三个新元素添加到数组中。如果指定的数组中只包含一个元素,那么等同于和没有使用$each”的普通的“$push”操作。

    db.stock.ticket.insert({"_id":"goog"})
    WriteResult({ "nInserted" : 1 })
    >  db.stock.ticket.update(
    ... ... ... {"_id":"goog"},
    ... ... ... {"$push":{"hourly":{"$each":[562.776,562.790,559.123]}}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.stock.ticket.findOne()
    { "_id" : "goog", "hourly" : [ 562.776, 562.79, 559.123 ] }

    要实现上面的操作,下面方法也可以。

    db.stock.ticket.update(
    ... ... ... ... ... {"_id":"goog"},
    ... ... ... ... ... {"$set":{"hourly":[562.776,562.790,559.123]}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.stock.ticket.findOne()
    { "_id" : "goog", "hourly" : [ 562.776, 562.79, 559.123 ] }

    而下面这样是不行的

     db.stock.ticket.update(
    ... ... ... ... {"_id":"goog"},
    ... ... ... ... {"$push":{"hourly":[562.776,562.790,559.123]}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.stock.ticket.findOne()
    { "_id" : "goog", "hourly" : [ [ 562.776, 562.79, 559.123 ] ] }
  • 相关阅读:
    申通完美支撑“双11”——亿级包裹背后的云基础设施
    你不知道的云服务器付费新模式,省钱就靠它了
    从“虚拟化”到“新基建”,云计算如何继续乘风破浪?
    Alibaba Cloud Linux 2 LTS 快速启动优化实践
    Alibaba Cloud Linux 2 LTS 正式发布,提供更高性能和更多保障!
    连续四年,神龙又扛住了“双11”
    飞天丨想象没有边界,创造改变未来
    清华大学高琪瑞:基于云端视觉计算建设全球先进的工科实验教学平台
    映客高级技术总监黄继:7天从开发到上线,云上高效运维实践与探索
    三维家如何借助云变革家居行业
  • 原文地址:https://www.cnblogs.com/ginb/p/6184916.html
Copyright © 2011-2022 走看看