MongoDB插入和删除文档

TrumanWong
7/13/2024
TrumanWong

本文介绍将数据移入和移出数据库的基本操作,具体包括以下几个方面:

插入文档

插入操作是向 MongoDB 中添加数据的基本方法。可以使用集合的 insertOne 方法插入单个文档:

video> db.movies.insertOne({"title" : "Stand by Me"})
{
  acknowledged: true,
  insertedId: ObjectId('668ce140aead5ca7a81b157d')
}

insertOne 会为文档自动添加一个 _id 键(如果你没有提供的话),并将其保存到MongoDB 中。

insertMany

语法:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

参数说明:

参数类型说明
documentdocument要插入到集合中的文档数组。
writeConcerndocument可选参数。表达写关注的文档。省略以使用默认写关注。如果是在事务中运行,则请勿显式设置此操作的写关注。要将写关注与事务一起使用,请参阅事务和写关注。
orderedboolean可选参数。布尔值,是否应执行有序或无序插入。默认为true

如果要向一个集合中插入多个文档,那么可以使用 insertMany。此方法可以将一个文档数组传递到数据库。这是一种更加高效的方法,因为代码不会为插入的每个文档去请求数据库,而是会批量插入它们。

video> db.movies.drop()
true
video> db.movies.insertMany([
... {"title" : "Ghostbusters"},
... {"title" : "E.T."},
... {"title" : "Blade Runner"}]);
{
  acknowledged: true,
  insertedIds: {
    '0': ObjectId('668ce194aead5ca7a81b157e'),
    '1': ObjectId('668ce194aead5ca7a81b157f'),
    '2': ObjectId('668ce194aead5ca7a81b1580')
  }
}
video> db.movies.find()
[
  { _id: ObjectId('668ce194aead5ca7a81b157e'), title: 'Ghostbusters' },
  { _id: ObjectId('668ce194aead5ca7a81b157f'), title: 'E.T.' },
  { _id: ObjectId('668ce194aead5ca7a81b1580'), title: 'Blade Runner' }
]

如果 ordered 设置为 true 并且插入失败,则服务器不会继续插入记录。

在这个例子中,因为默认情况下为有序插入,所以只有前两个文档会被插入集合中。第三个文档将产生一个错误,因为不能插入两个具有相同 _id 的文档:

> db.movies.insertMany([
... {"_id" : 0, "title" : "Top Gun"},
... {"_id" : 1, "title" : "Back to the Future"},
... {"_id" : 1, "title" : "Gremlins"},
... {"_id" : 2, "title" : "Aliens"}])
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: videos.movies index: _id_ dup key: { _id: 1 }
Result: BulkWriteResult {
  insertedCount: 2,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 0, '1': 1 }
}
Write Errors: [
  WriteError {
    err: {
      index: 2,
      code: 11000,
      errmsg: 'E11000 duplicate key error collection: videos.movies index: _id_ dup key: { _id: 1 }',
      errInfo: undefined,
      op: { _id: 1, title: 'Gremlins' }
    }
  }
]
> db.movies.find()
[
  { _id: 0, title: 'Top Gun' },
  { _id: 1, title: 'Back to the Future' }
]

如果 ordered 设为 false 且插入操作失败,服务器会继续插入记录。文档可按 mongod 重新排序,从而提高性能。

> db.movies.insertMany([
... {"_id" : 3, "title" : "Sixteen Candles"},
... {"_id" : 4, "title" : "The Terminator"},
... {"_id" : 4, "title" : "The Princess Bride"},
... {"_id" : 5, "title" : "Scarface"}],
... {"ordered" : false})
Uncaught:
MongoBulkWriteError: E11000 duplicate key error collection: videos.movies index: _id_ dup key: { _id: 4 }
Result: BulkWriteResult {
  insertedCount: 3,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds: { '0': 3, '1': 4, '3': 5 }
}
Write Errors: [
  WriteError {
    err: {
      index: 2,
      code: 11000,
      errmsg: 'E11000 duplicate key error collection: videos.movies index: _id_ dup key: { _id: 4 }',
      errInfo: undefined,
      op: { _id: 4, title: 'The Princess Bride' }
    }
  }
]
> db.movies.find()
[
  { _id: 0, title: 'Top Gun' },
  { _id: 1, title: 'Back to the Future' },
  { _id: 3, title: 'Sixteen Candles' },
  { _id: 4, title: 'The Terminator' },
  { _id: 5, title: 'Scarface' }
]

每组中的操作次数不得超过数据库的 maxWriteBatchSize 值。maxWriteBatchSize 的默认值为 100,000。该值会显示在 hello.maxWriteBatchSize 字段中。

此限制可防止错误消息过大的问题。如果一个群组超过此限制,则客户端驱动程序会将该群组分成计数小于或等于限制值的更小群组。例如,对于 maxWriteBatchSize 值为 100,000 的情况,如果队列由 200,000 个操作组成,则驱动程序将创建 2 个群组,每个群组包含 100,000 个操作。

在分片集合上执行操作的 ordered 列表通常比执行 unordered 列表慢,因为对于有序列表,每个操作都必须等待前一个操作完成。

插入校验

如果文档未指定 _id 字段,mongod 则会添加 _id 字段并为该文档分配一个唯一 ObjectId()。大多数驱动程序均会创建一个 ObjectId 并插入 _id 字段;如果驱动程序或应用程序未执行上述操作,mongod 则会创建并填充 _id

如果文档包含 _id 字段,则 _id 值在集合中必须是唯一的,以避免重复键错误。

删除文档

MongoDB 提供了以下 方法来删除集合中的文档:

db.collection.deleteOne()即使多个文档可能与指定筛选器匹配,最多也只删除与指定筛选器匹配的单个文档。
db.collection.deleteMany()删除所有与指定筛选器匹配的文档。
db.collection.remove()删除与指定过滤器匹配的单个文档或所有文档。

以下方法还可以从集合中删除文档:

deleteOne

db.collection.deleteOne() 会删除与过滤器匹配的第一个文档。使用作为唯一索引一部分的字段(例如 _id)进行精确删除。如下所示:

> db.movies.find()
[
  { _id: 0, title: 'Top Gun' },
  { _id: 1, title: 'Back to the Future' },
  { _id: 3, title: 'Sixteen Candles' },
  { _id: 4, title: 'The Terminator' },
  { _id: 5, title: 'Scarface' }
]
> db.movies.deleteOne({"_id": 4})
{ acknowledged: true, deletedCount: 1 }

deleteMany

db.collection.deleteMany() 用于从集合中删除与 filter 匹配的所有文档。示例如下:

> db.movies.deleteMany({})
{ acknowledged: true, deletedCount: 4 }
>  db.movies.insertMany([{ "_id" : 0, "title" : "Top Gun", "year" : 1986 },
... { "_id" : 1, "title" : "Back to the Future", "year" : 1985 },
... { "_id" : 3, "title" : "Sixteen Candles", "year" : 1984 },
... { "_id" : 4, "title" : "The Terminator", "year" : 1984 },
... { "_id" : 5, "title" : "Scarface", "year" : 1983 }])
{
  acknowledged: true,
  insertedIds: { '0': 0, '1': 1, '2': 3, '3': 4, '4': 5 }
}
> db.movies.deleteMany({"year": 1984})
{ acknowledged: true, deletedCount: 2 }
> db.movies.find()
[
  { _id: 0, title: 'Top Gun', year: 1986 },
  { _id: 1, title: 'Back to the Future', year: 1985 },
  { _id: 5, title: 'Scarface', year: 1983 }
]

删除集合

可以使用 deleteMany 来删除一个集合中的所有文档:

> db.movies.deleteMany({})
{ acknowledged: true, deletedCount: 3 }
> db.movies.find()

删除文档的操作通常会比较快。不过,如果想清空整个集合,那么使用 drop 直接删除集合,然后在这个空集合中重建各项索引会更快:

> db.movies.drop()
true

数据删除是永久性的。没有任何方法可以撤回删除文档或者删除集合的操作,也无法恢复被删除的文档,当然从以前的备份中恢复除外。