2_MongoDB基础使用

MongoDB学习

二. 创建、更新及删除文档

1. 插入并保存文档

db.foo.insert({'bar': 'bar'})

  1. 这个操作会给document增加一个_id键(要是原理没有的话),然后保存到MongoDB中。

  2. 如果插入多个document,应该使用批量插入,他接受一个由文档组成的数组。批量插入只能用于将多个document插入到一个collection,不可用于插入多个collection。

  3. 插入的原理和作用:

    当执行插入的时候,驱动程序会把数据转换成BSON,然后将其送入数据库。数据库解析BSON,检查是否包含_id且文档小于4MB,不做数据验证

2. 删除文档

db.users.remove()

  1. 这样删除不会删除collection本身,也不会删除索引。
  2. 从删除速度上来讲,删除一个collection并重建索引比删除一个collection中的所有document通常更快
3. 更新文档

使用update来更新document,通常有两个参数,第一个是查询文档,用于查找到用于删除的文档,另一个是修改器文档,描述对document做哪些修改。

注意:当我们更新文档时,最好使用类如_id这样的,可以单独选出唯一文档的条件,否则可能报错

修改器
  1. $inc

    $inc可以用来增加已有键的值,如果这个键不存在,则创建这个键

    假设存在以下结构:

    {
        "_id": ObjectId("......"),
        "url": "www.example.com",
        "pageviews": 52
    }
    db.analytics.update(
        {'url': 'example'},
        {'$inc': {
            {'pageviews': 1}
        } 
    )
  2. $set

    set使 unset删除键。

    > db.users.findOne()
    {
        "_id": ObjectId("123456"),
        "name": "joe",
        "age": 30,
        "sex": "male",
        "location" : "HZ"
    }

    使用$set**添加**一个键:

    > db.users.update(
        {"_id": "123456"}, 
        {"$set": {"favorite book": "peace and war"}
    )
    {
        "_id": ObjectId("123456"),
        "name": "joe",
        "age": 30,
        "sex": "male",
        "location" : "HZ",
        "favorite book": "peace and war"
    }
    

    使用$set**修改**一个键的值(可以更换这个键的值得数据类型!):

    db.users.update(
        {"_id": "123456"}, 
        {"$set": {"favorite book": "what's up!"}
    )
    {
        "_id": ObjectId("123456"),
        "name": "joe",
        "age": 30,
        "sex": "male",
        "location" : "HZ",
        "favorite book": "what's up!"
    }

    使用$unset**删除**一个键:

    db.users.update(
        {"_id": "123456"}, 
        {"$unset": {"favorite book": 1}
    )

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

  3. 数组修改器

    $push,如果这个键不存在,则创建一个数组,如果存在且是一个数组则插入到尾部。

    > db.blog.posts.findOne()
    {
        "_id": ObjectId('123456'),
        "title": "A blog post",
        "content": "......"
    }
    
    > db.blog.posts.update(
        {"title": "A blog post"},
        {
            "$push": {
                "comments": {
                    "name": "ldd",
                    "title": "nice post",
                    "content": "lalala"
                }
            }
        }
    )
    
    > db.blog.posts.findOne()
    {
        "_id": ObjectId('123456'),
        "title": "A blog post",
        "content": "......",
        "comments": [
            {
                "name": "ldd",
                "title": "nice post",
                "content": "lalala"
            }
        ]
    }

    $addToSet,如果数组中已经存在这个值,则什么也不做;否则加入数组

    > db.users.findOne();
    {
        "_id": ObjectId("123456"),
        "username": "ldd",
        "emails": [
            "ldd@example.com",
            "ldd@gmail.com",
            "ldd@yahoo.com"
        ]
    }
    
    // 第一次添加时因为已经有了这个邮箱,所以原来的document不变
    > db.users.update(
        {
            "_id": "123456"
        },
        {
            "$addToSet": {
                "eamils": "ldd@gmail.com"
            }
        }
    )
    
    > db.users.findOne();
    {
        "_id": ObjectId("123456"),
        "username": "ldd",
        "emails": [
            "ldd@example.com",
            "ldd@gmail.com",
            "ldd@yahoo.com"
        ]
    }
    
    // 第二次添加成功
    > db.users.update(
        {
            "_id": "123456"
        },
        {
            "$addToSet": {
                "eamils": "ldd@hotmail.com"
            }
        }
    )
    
    > db.users.findOne();
    {
        "_id": ObjectId("123456"),
        "username": "ldd",
        "emails": [
            "ldd@example.com",
            "ldd@gmail.com",
            "ldd@yahoo.com",
            "ldd@hotmail.com"
        ]
    }

    使用 addToSet each添加一个数组到数组

    db.users.update(
        {"_id": "ObjectId('123456')"},
        {"$addToSet": {
            "emails": {
                $each: [
                    "ldd@example.com",
                    "ldd@gmail.com",
                    "ldd@yahoo.com",
                    "ldd@hotmail.com"
                ]
            }
        }}
    )

    使用$pop删除一端的元素,{"$pop": {"key": 1}}从数组末尾删除一个元素,{"$pop": {"key": -1}}从头删除一个元素。

    使用$pull在列表中进行精确的删除,它会删除所有匹配的数据

    {"$pull": {
        "todo": "laundry"
    }}
  4. 数组的定位修改器

    如果数组中有多个数据,可以使用$来匹配第一个匹配到的数据。

    > db.blog.posts.findOne()
    {
        "_id": ObjectId('123456'),
        content: "......",
        comments: [
            {
                "name": "ldd",
                "title": "nice post",
                "content": "lalala",
                "votes": 0
            },
            {
                "name": "lll",
                "title: "a nice post",
                "content": "wowoow",
                "votes": 0
            }
        ]
    }
    
    db.blog.update(
        {"comments.author": "ldd"},
        {"$set": {"comments.$.name": "zhu"}}
    )
upsert

upsert是一种特殊的更新,要是没有文档符合更新条件,就以这个条件以及document更新为基础创建一个新的document,如果找到了文档则正常更新。

要使用upsert,只要把update的第三个参数设为true即可。

比如说我们给一个博客加pageview,一开始的时候并没有这个url,使用upsert可以初始化,之后有了这个url,则正常更新(更实际的应该是在初始化这个博客的时候就把pageview赋为0了把?)

blog = db.posts.findOne({"url": "/blog"});

if (blog) {
    blog.pageview ++;
    db.posts.save(blog);
}
else {
    db.posts.save({"url": "/blog", "pageview": 1});
}

如果使用upsert,上面的代码用一句话代替:

db.posts.update({"url": "/blog"}, {$inc: {"pageview": 1}}, true);

在shell中快速修改document的方法。save方法被调用时,如果文档中有_id键,则自动使用upsert,否则不会,调用插入。

> var x = db.foo.findOne();
> x.num = 42;
42
>db.foo.save(x);
更新多文档

通常情况下,update操作只会操作第一个满足匹配条件的文档。因此,如果有多个document满足条件则其他的不会被update。

要让所有满足匹配条件的document都update,则应让第四个参数为true。

比如我们要让在特定日期过生日的用户收到礼物:

db.users.update(
    {birthday: "1994/01/19"},
    ...,
    {$set: {"gift": "Happy birthday}},
    false,
    true
)

那么我们如何知道有多少文档被更新了呢???

> db.count.update({x: 1}, {$inc: {x: 1}, false, true)
> db.runCommand({getLastError: 1})
{
    "err": null,
    "updateExisting": true,
    "n": 5,
    "ok": true
}

其中,n表示修改的document的个数,updateExisting为true表示修改的是已有document。

返回更新的文档

如果时序关系很重要的话,则可以考虑findAndModify操作

一个例子:有如下形式的document

{
    "_id": ObjectId('123456'),
    "status": "READY",
    "priority": n
}

我们要从READY中选出priority最高的进行操作。

ps = db.processes.find({"status": "READY"})
                    .sort({"priority": -1})
                    .limit(1)
                    .next();
db.processes.update({"_id": ps._id}, {"$set": {"status": "RUNNING"}});
do_something(ps);
db.processes.update({"_id": ps._id}, {"$set": {"status": "DONE"}});

如果线程A执行第二句话之前,线程B也执行了第一句话,则出现冲突。

这时候使用findAndModify:

> ps = db.runCommand({
    "findAndModify": "processes",
    "query": {"status": "READY"},
    "sort": {"priority": -1},
    "update": {"$set": {"status": "RUNNING"}}
})
{
    "ok": 1,
    "value": {
        "_id": ObjectId("123456"),
        "priority": 1,
        "status: "READY"
    }
}

先返回结果,后更新

> db.processes.find({"_id": ps.value._id})
{
    "_id": ObjectId("123456"),
    "priority": 1,
    "status: "RUNNING"
}

所以,程序就变成了这个样子:

> ps = db.runCommand({
    "findAndModify": "processes",
    "query": {"status": "READY"},
    "sort": {"priority": -1},
    "update": {"$set": {"status": "RUNNING"}}
}).value
> do_somethind(ps)
> db.processes.update({"_id": ps._id"}, {"$set": {"status": "DONE"}})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值