MongonDB--创建更新和删除文档

MongonDB–创建更新和删除文档

一:插入并且保存文档

1. 插入单条数据
test>var post={"title":"hello","conent":"你好世界","style":"luck"}
test>post
{ "title" : "hello", "conent" : "你好世界", "style" : "luck" }
test>db.blog.post.insert(post)
WriteResult({ "nInserted" : 1 })
2. 插入批量数据

使用批量插入将一组文档传递给数据库

test>db.foo.batchInsert({"_id":0},{"_id":1},{"_id":2})
2019-11-22T10:21:31.251+0800 E QUERY    [thread1] TypeError: db.foo.batchInsert is not a function :
@(shell):1:1

使用batchInsert()发现显示没有这个函数,百度后说这个方法已经过时,现在使用insert就可以直接批量插入了

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

注意:

1.shell中只能将多个文档导入到一个集合中,不能直接将多个文档导入到多个集合中;可以使用mongoimport实现这个功能;

2.MongoDB当前版本能接受的最大的消息长度是48m,如果超过就会拆成多个小于等于48M的批量插入请求;不同的版本可能不同;

3.MongoDB批量插入式原子性的,每插入一个文档,如果用户没有指定_id,客户端会自动分配id,如当前文档插入操作错误,当前文档之后的文档都会插入失败;驱动程序中可以指定continueOnError选项,是否跳过当前错误继续插入,shell中不支持。

3. 数据校验

MongoDB只做最基本的校验,检查文档的基本结构,如果没有_id字段会自动增加;还要检查每一个文档的大小是否小于16M。

在shell中可以使用Object.basonsize(doc),来查看doc文档大小。一般是驱动程序在数据插入到数据库之前做大量的数据校验(文档是否过大,文档是否包含非UTF-8的字符串)

二:删除文档

1.删除语法remove()
1.1 删除所有文档
cqsm>db.mong.find()
{ "_id" : ObjectId("5dd7508179a009e570bfa6cf"), "title" : 12, "aa" : 21 }
cqsm>db.mong.remove()
2019-11-22T11:05:56.799+0800 E QUERY    [thread1] Error: remove needs a query :
DBCollection.prototype._parseRemove@src/mongo/shell/collection.js:357:1
DBCollection.prototype.remove@src/mongo/shell/collection.js:382:18
@(shell):1:1
cqsm>

发现出现错误,将db.mong.find()改成db.mong.remove({})问题得到解决

cqsm>db.mong.remove({})
WriteResult({ "nRemoved" : 1 })
cqsm>db.mong.find()
cqsm>
1.2 删除指定文档
cqsm>db.mong.remove({"title":12})
WriteResult({ "nRemoved" : 1 })
2.删除语法drop()
cqsm>db.mong.drop()
true
cqsm>db.mong.find()
cqsm>
3.drop和remove的区别

删除数据是永久的,不能撤销的,不能恢复的

1.remove({})删除所有文档,但是不会删除集合本身,也不会删除元数据;

2.drop()直接删除整个集合,删除了元数据;

3.drop()的删除速度比remove()快很多很多很多很多…

三:更新文档

1. 文档替换
创建一个文档
var post1={"name":"zs","age":"18","sex":"man"}
插入文档到集合中
db.mong.insert(post1)
查看文档
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "age" : "18",
        "sex" : "man"
}

现在想把age和sex归纳到一个新文档info中。可以建立一个两个新文档,一个新文档joe用来替换旧文档,一个文档info文档用来替换age和sex属性

cqsm>var joe=db.mong.findOne()//通过find()创建一个文档
cqsm>joe.info={"age":joe.age,"sex":joe.sex}//创建内嵌文档info
{ "age" : "18", "sex" : "man" }
cqsm>delete joe.age//删除了age
true
cqsm>delete joe.sex//删除了sex
true
cqsm>db.mong.update({"name":"zs"},joe)//替换
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "18",
                "sex" : "man"
        }
}

注意:替换文档的时候,参数一查询文档的时候最好使用唯一的不重复的键作为条件,避免错误,因为如果查询到了多个,不知道替换哪个。

2. 使用修改器
2.1 "$set"修改器

"$set"用来指定一个字段的值,如果这个字段不存在就去创建它。常用于更新模式或者增加用户定义的键。

2.1.1 增加键
原本的数据:
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "18",
                "sex" : "man"
        }
}
更新:
db.mong.update({"_id":ObjectId("5dd757a379a009e570bfa6d2")},{"$set":{"love":"bingpang"}})
更新之后:
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "18",
                "sex" : "man"
        },
        "love" : "bingpang"
}
2.1.2 修改值的类型

将love的值改为数组类型

db.mong.update({"_id":ObjectId("5dd757a379a009e570bfa6d2")},{"$set":{"love":["pangpang","bask","shoping"]}})
2.1.3 使用$unset删除某个键

删除将love键以及值

db.mong.update({"_id":ObjectId("5dd757a379a009e570bfa6d2")},{"$unset":{"love":1}})
2.1.4 修改内嵌文档

原本的文档:

cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "20",
                "sex" : "man"
        }
}

首先按照MongoDB第二版上面的写法,会发现写不进去

cqsm>db.mong.info.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$set":{"info.age":"22"}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
cqsm>

修改后,可以写入了,关键是.连接,只需要写在"$set"后的值

cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$set":{"info.age":"22"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        }
}
2.2 "$sin"修改器

"$sin"用来对数值增加或者减少,对于已有主键的就修改值,没有主键的就创建主键添加值

不存在主键,添加主键和值:

cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$inc":{"score":50}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 50
}

存在主键,更新值:

#增加值
cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$inc":{"score":500}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 550
}

#减少值
cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$inc":{"score":-500}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 50
}

注意:

"$inc"键的值必须是数字,只能是整形,长整形,双精度浮点型

2.3 数组修改器
2.3.1 添加元素("$push")

如果数组存在就会向数组末尾添加一个新的元素,如果数组不存在就会创建新数组

cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$push":{"love":{"love1":1,"love2":2,"love3":3}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 50,
        "love" : [
                {
                        "love1" : 1,
                        "love2" : 2,
                        "love3" : 3
                }
        ]
}

添加已存在的数组:
cqsm>db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$push":{"love":{"love4":4}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 50,
        "love" : [
                {
                        "love1" : 1,
                        "love2" : 2,
                        "love3" : 3
                },
                {
                        "love4" : 4
                }
        ]
}

使用" e a c h " 配 合 " each"配合" each""push"使用可以一次性添加多个值

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$push":{"love":{"$each":[{"love5":5},{"love6":6},{"love7":7}]}}})

注意:一定一定一定一定要注意,有键值对的数组数据一定要用{}包起来,不然一定会报错

使用" s l i c e " 配 合 " slice"配合" slice""push"使用可以使数组的长度固定,还可以使用"$slice"对数组中对象进行排序。

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$push":{"like":{"$each":[1,2,3,4,5,6,7,8,9,10,11,12],"$slice":-6}}})

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$push":{"like":{"$each":[{"age":12},{"age":13},{"age":1},{"age":22}],"$slice":-2,"$sort":{"age":-1}}}})
2.3.2 将数组作为数据集使用

可以使用"$ne"判断数组中的元素是否存在;如果不存在就添加进去

db.mong.update({"like":{"$ne":5},{"$push":{"love5":5}})

在一些情况下"$ne"用不了,就可以使用"addToset"来避免重复插入

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$addToSet":{"like":{"like1":1,"like2":2}}})

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$addToSet":{"like":{"like3":4}}})

还可以将" a d d T o S e t " 和 " addToSet"和" addToSet""$each"搭配起来使用一次插入多个

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$addToSet":{"like":{"$each":[{"like4":4,"like5":5},{"like6":4,"like7":5}]}}})

总结:

  • "$set"是用于update()的第一个参数,用于筛选,作为条件;
  • "$addToSet"用于update()第二个参数,用于避免重复;
  • “[ ]“中有多个”{}”
2.3.3 删除数组中元素

可以通过"KaTeX parse error: Expected '}', got 'EOF' at end of input: …"从数组任何一端删除元素,{"pop":{“key”:1}}表示从数组末尾删除元素,{"$pop":{“key”:-1}}表示从数组头部删除元素

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$pop":{"like":-1}})

还可以使用"$pull"删除基于特定条件的数组元素

db.mong.update({},{"$pull":{"love":{"love6" : 6}}})

db.mong.update({"_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$pull":{"love":{"love5" : 5}}})

总结:

  • 使用"$pull",update的第一个参数可以视情况选择;
  • " p u l l " 和 " pull"和" pull"" u n s e t " 是 不 同 的 , " unset"是不同的," unset""unset"删除某个键,可以一次删除数组,而”$pull"是针对数组使用,删除数组中的元素;
  • inert可以一次插入多个元素,each是一次性更新多个元素,each针对数组;
2.3.4 基于位置的数据修改器

例如如果想修改数组中某个值可以这样做:使用’ . '连接

cqsm>db.mong.update({ "_id" : ObjectId("5dd757a379a009e570bfa6d2")},{"$inc":{"love.0.love1":6}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
cqsm>db.mong.findOne()
{
        "_id" : ObjectId("5dd757a379a009e570bfa6d2"),
        "name" : "zs",
        "info" : {
                "age" : "22",
                "sex" : "man"
        },
        "score" : 50,
        "love" : [
                {
                        "love1" : 7,
                        "love2" : 2,
                        "love3" : 3
                },
                22,
                33,
                44
        ]
}

由于很多时候不能预先知道要修改数组的下标,我么还可以使用"$"连接符,它用来定位查询文档匹配到的数组下标

db.mong.update({"love.love1":7},{"$inc":{"love.$.love1":2}})
2.4 关于修改器的速度
  • $inc由于不需要移动文档,可以直接修改值,所以速度比较快;
  • $set除非在文档不发生变化修改,不然性能也不好;
  • 数组修改器可能会改变文档大小,所以也会慢一些;
为何$push会有瓶颈?

在这里插入图片描述

1.MongoDB上文档是顺序存储的,而且文档是原子性的,在执行更新操作之前,会为每个文档分配精确地空间。

2.当使用$set将"x":“b"修改为"x”:"bob"时候,原本的空间就放不下了,这个文档就因为体积变大进行移动,它原本占的空间就空下来了,而且填充因子会增加为1.5。

3.之后$push插入的文档会拥有填充因子指定大小的增长空间,如果不在发生文档移动,填充因子会逐渐减小。

移动文档很慢,要先释放掉原本占用的空间再将文档写入到另一片空间。经常移动文档会产生大量的空白空间,如果在进行插入和删除的时候大量移动文档或者打乱数据,可以进行如下的设置提高磁盘复用率

db.runCommand({"colMod":collectionName,"usePowerOf2Sizes":true})

这样设置之后,集合上空间的分配都是2的幂,导致初始空间分配不高效

3. 特殊的更新–upsert
3.1 upset

upset既可以创建文档又可以更新文档,如果存在就更新不存在就创建。update()的第三个参数就是代表着upsert.

db.mong.update({"eat":"ba"},{"eat":"baaaa"},true)

db.coll.update({"eat":20},{"$inc":{"eat":2}},true)
3.2 $setOnInsert

使用$setOnInsert()会在创建文档的时候创建字段并且赋值,在之后的更新操作中如果不是创建就不会改变字段的值

第一次执行,创建
cqsm>db.coll.update({"like":1},{"$setOnInsert":{"like":1}},true)
cqsm>db.coll.find()
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "a" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716d"), "x" : "b" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5dda60fb7a8eb11f45c159ab"), "eat" : 22 }
{ "_id" : ObjectId("5dda641f7a8eb11f45c159bd"), "like" : 1 }

第二次执行,{"like":1}这个文档已经存在,所以不会更改字段的值
cqsm>db.coll.update({"like":1},{"$setOnInsert":{"like":3}},true)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
cqsm>db.coll.find()
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "a" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716d"), "x" : "b" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5dda60fb7a8eb11f45c159ab"), "eat" : 22 }
{ "_id" : ObjectId("5dda641f7a8eb11f45c159bd"), "like" : 1 }

3.3 save shell帮助程序

save是一个shell函数,他只有一个参数,就是文档,如果文档存在就更新(update),不存在就创建(insert)。

cqsm>var x=db.coll.findOne()
cqsm>x
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "a" }
cqsm>db.mong.save(x)
4.更新多个文档

update的第四个参数的设置决定是否更新匹配到的多个文档还是只更新第一个文档

db.mong.update({"x":"c"},{"$set":{"x":"ccccc"}},false,true)

可以使用runCommand(getLastError : 1)查看更新多少个文档,n代表更新了多少个文档

cqsm>db.runCommand({getLastError : 1})
{
        "connectionId" : 3,
        "updatedExisting" : true,
        "n" : 3,
        "syncMillis" : 0,
        "writtenTo" : null,
        "err" : null,
        "ok" : 1
}
5.findAndModify 返回被更新的文档

findAndModify命令有多个可以使用的字段

  • findAndModify:字符串,集合名
  • query:查询文档,用于检索文档的条件
  • sort:排序结果的条件
  • update:修改器文档,用于对匹配的文档进行更新(update和remove必须指定一个)
  • remove:布尔类型,表示是否删除文档
  • new:布尔类型,表示返回的是更新前的文档还是更新后的文档,默认更新前
  • fields:布尔类型,值为true的时候表示这是一个upset.默认false

remove和update必须指定一个,不然会报错

cqsm>var ps=db.runCommand({"findAndModify":"coll","query":{"x":"a"},"sort":{"x":-1},"update":{"x":"aaa"},"new":true})
cqsm>ps
{
        "lastErrorObject" : {
                "n" : 1,
                "updatedExisting" : true
        },
        "value" : {
                "_id" : ObjectId("5dda13e73ee0f76ee97c716c"),
                "x" : "aaa"
        },
        "ok" : 1
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值