MongoDB数据变更
插入文档
1、插入一条
>db.test.insertOne(“title”:“test”)
2、批量插入
>db.test.insertMany([{“title”:“test”},{“title”:“hello”},…])
一次发送数十、数百甚至数千个文档会明显提高插入的速度。
注:
如果要将多个文档插入单个集合中,那么 insertMany 将非常有用。但如果只是导入原始数据(例如,从数据源或 MySQL 中导入),则可以使用像 mongoimport这样的命令行工具,而不是批量插入。另外,在将数据存入 MongoDB 之前,可以使用批量插入对其做一些小的修整(比如将日期转换为日期类型,或者添加自定义的 “_id”)。在这种情况下,insertMany 同样可以用于导入数据。
在当前版本中,MongoDB 能够接受的最大消息长度是 48MB,因此在单次批量插入中能够插入的文档是有限制的。如果尝试插入超过 48MB 的数据,则多数驱动程序会将这个批量插入请求拆分为多个 48MB 的批量插入请求。详情请查看所使用驱动程序的相关文档。
在使用 insertMany 执行批量插入时,如果中途某个文档发生了某种类型的错误,那么接下来会发生什么取决于所选择的是有序操作还是无序操作。可以指定一个选项文档作为 insertMany 的第二个参数。将选项文档中的 “ordered” 键指定为true,可以确保文档按提供的顺序插入。指定为 false 则允许 MongoDB 重新排列插入的顺序以提高性能。如果未特别指定,则默认为有序插入。对于有序插入,插入顺序由传递给 insertMany 的数组进行定义。如果一个文档产生了插入错误,则数组中在此之后的文档均不会被插入集合中。对于无序插入,MongoDB 将尝试插入所有文档,而不管某些插入是否产生了错误。
注:所有文档都必须小于 16MB。在 shell 中执行 Object.bsonsize(doc)可查看 doc 文档的二进制 JSON(BSON)大小(以字节为单位)
由于仅做最基本的检查,这意味着可以很容易地插入无效数据(如果你尝试这么做的话)。因此,应该只允许受信任的源(比如应用程序服务器)连接到数据库。所有主流语言的 MongoDB 驱动程序以及大部分其他语言的驱动程序,在向数据库发送任何内容之前,都会进行各种无效数据的校验(比如文档过大、包含非 UTF-8字符串,或使用无法识别的类型)。
在 MongoDB 3.0 之前,insert 是在 MongoDB 中插入文档的主要方法。在 3.0版本的服务器端发布时,MongoDB 驱动程序引入了新的 CRUD API。从MongoDB 3.2 开始,mongo shell 也支持这种 API,它包括 insertOne 和insertMany 以及其他一些方法。当前 CRUD API 的目标是使所有 CRUD 操作的语义在驱动程序和 shell 之间保持一致和清晰。虽然 insert 等方法仍然支持向后兼容,但今后不应该在应用程序中继续使用。应该使用 insertOne 和 insertMany 来创建文档。
删除文档
CRUD API 为此提供了 deleteOne 和deleteMany 两种方法。这两种方法都将筛选文档(filter document)作为第一个参数。筛选文档指定了在删除文档时要与之匹配的一组条件。
>db.test.deleteOne({“name”:“zhangsan”})
>db.test.deleteMany({“name”:“zhangsan”})
删除文档的操作通常会比较快,因为只是做一下标记,并没有将数据文件删除,重新写入的时候,会进行覆盖。
>db.test.drop()
数据删除是永久性的。没有任何方法可以撤回删除文档或者删除集合的操作,也无法恢复被删除的文档,当然从以前的备份中恢复除外
更新文档
文档替换
>db.test.replaceOne({query},{doc})增加数量
>db.test.updateOne({query},{$inc:{“age”:1}})设置姓名
>db.test.updateOne({query},{$set:{“name”:“lisi”}})移除属性
>db.test.updateOne({query},{$unset:{“name”:“zhangsan”}})数组添加元素
>db.test.updateOne({query},{$push:{“comments”:{“name”:“test”,“email”:“xxx@xx.com”}}})数组添加多个元素
>db.test.updateOne({query},{$push:{“arr”:{$each:[1,2,3,4]}}})topN场景,数组只保留最后加入的 10 个元素
>db.test.updateOne({query},{“$push”:{“$each”:[1,2,3,4,5],“$slice”:-10}})topN场景,排序之后数组只保留最后加入的 10 个元素
>db.test.updateOne({query},{“$push”:{“$each”:[{“name”:“test”,“email”:“xxx@xx.com”},{“name”:“test1”,“email”:“xxx@xx.com”},{“name”:“test2”,“email”:“xxx@xx.com”}],“sort”:{“name”:-1}}})
数组中不存在则添加
db.test.updateOne({“arr”:{$ne:“zhangsan”}},{$push:{“arr”:“zhangsan”}})
使用 “$addToSet” 来避免插入重复的数据到数组中
db.test.updateOne({query},{“$addToSet”:{“arr”:“elem1”}})
使用 “$addToSet” 来避免插入重复的数据到数组中
db.test.updateOne({query},{“$addToSet”:{“arr”:{“$each”:[“elem1”,“elem2”]}}})
删除元素,使用 “KaTeX parse error: Expected '}', got 'EOF' at end of input: …p" 从任意一端删除元素。{"pop” : {“key” : 1}} 会从数组末尾删除一个元素,{“$pop” : {“key” : -1}} 则会从头部删除它。
有时需要根据特定条件而不是元素在数组中的位置删除元素。“$pull” 用于删除与给定条件匹配的数组元素。
db.test.updateOne({query},{“$pull”:{“arr”:“1”}})
基于位置的数组更改,数组使用从 0 开始的下标,可以将下标当作文档的键来选择元素
db.test.updateOne({query},{“$inc”:{arrs.0.name:1}})
在很多情况下,如果不预先查询文档并进行检查,就不知道要修改数组的下标。为了解决这个问题,MongoDB 提供了一个定位运算符 $,它可以计算出查询文档匹配的数组元素并更新该元素。
db.test.updateOne({query},{“$set”:{“arrs.$.name”:“test”}})
使用数组过滤器进行更新。MongoDB 3.6 引入了另一个用于更新单个数组元素的选项:arrayFilters。
db.test.updateOne(
{“_id”:id},
{“$set”:{“arrs.$[elem].hidden”:true}},
{
arrayFilters:[{“elem.votes”:{“$lte”:-5}}]
}
)
upsert 是一种特殊类型的更新。如果找不到与筛选条件相匹配的文档,则会以这个条件和更新文档为基础来创建一个新文档;如果找到了匹配的文档,则进行正常的更新。
>db.test.updateOne({query},{“$inc”:{“age”:1}},{“upsert”:true})
有时候需要在创建文档时对字段进行设置,但在后续更新时不对其进行更改。这就是 “setOnInsert” 是一个运算符,它只会在插入文档时设置字段的值。
>db.test.updateOne({},{“$setOnInsert”:{“createAt”:new Date()}},{“upsert”:true})
save 是一个 shell 函数,它可以在文档不存在时插入文档,在文档存在时更新文档。
更新多个文档可以使用updateMany
返回被更新的文档
在某些场景中,返回修改过的文档是很重要的。在 MongoDB 的早期版本中,findAndModify 是这种情况下的首选方法。它对于操作队列和执行其他需要取值、赋值的原子操作来说非常方便。不过,findAndModify 很容易出现用户错误,因为它非常复杂,结合了 3 种不同类型操作的功能:删除、替换和更新(包括upsert)。
MongoDB 3.2 向 shell 中引入了 3 个新的集合方法来提供 findAndModify 的功能,但其语义更易于学习和记忆:findOneAndDelete、findOneAndReplace 和findOneAndUpdate。这些方法与 updateOne 之间的主要区别在于,它们可以原子地获取已修改文档的值。MongoDB 4.2 扩展了 findOneAndUpdate 以接受一个用来更新的聚合管道。管道可以包含以下阶段:$addFields 及其别名 $set、$project 及其别名 $unset,以及 $replaceRoot 及其别名 $replaceWith。