【翻译】MongoDB指南/CRUD操作(二)

【原文地址】https://docs.mongodb.com/manual/

MongoDB CRUD操作(二)

主要内容:

更新文档,删除文档,批量写操作,SQL与MongoDB映射图,读隔离(读关注),写确认(写关注)

1 更新文档

1.1 更新

MongoDB提供下列方法用于更新一个集合


db.collection.updateOne()


更新使用指定过滤器匹配到的文档,即使过滤器匹配到多个文档,也只会更新一个文档。

3.2版本新增特性。


db.collection.updateMany()


更新使用指定过滤器匹配到的所有文档。

3.2版本新增特性。


db.collection.replaceOne()


替换使用指定过滤器匹配到的文档,即使过滤器匹配到多个文档,也只会更新一个文档。

3.2版本新增特性。


db.collection.update()


更新或者替换一个使用指定过滤器匹配到的文档,或者更新使用指定过滤器匹配到的所有文档。

默认只更新一个文档。为了更新多个文档,请使用multi 选项。

上述方法接受以下参数:

  • 过滤器文档,确定要更新哪些文档。这些过滤器与查询操作中使用的过滤器有相同的句法规则。
    •   查询过滤器文档,使用表达式<field>:<value>指定相等条件,找出所有字段<field>的值为<value>的文档:

        { <field1>: <value1>, ... }

    •   查询过滤器文档,可使用查询操作符指定条件:

        { <field1>: { <operator1>: <value1> }, ... }

  • 指定了更新内容的更新文档;或一个替换的文档,替换掉匹配到的文档而保持_id字段不变。
  • 一个选项文档。

1.2 行为

原子性

MongoDB 中写操作在单文档级别具有原子性。

_id字段

文档一旦创建,_id字段值就固定了,不能被更新,也不能用一个_id字段值与原文档不同的文档来替换原文档。

文档大小

当执行更新操作时,导致文档变大并超出已分配的大小时,更新操作会在磁盘上重新定位文件。

字段顺序

MongoDB 保持字段写入时的顺序,除非遇到下列情况:

  • _id字段总是处在首位。
  • 更新的时候对某一个或某些字段重命名可能导致字段顺序变更

2.6版本中的变化:从2.6版本开始,MongoDB 尽可能地保持字段写入时的顺序,但之前的版本并不是这样的。

Upsert 选项

如果db.collection.update(), db.collection.updateOne(), db.collection.updateMany(), 或者db.collection.replaceOne()包括

“upsert : true”并且使用指定的过滤器没有匹配到任何文档,那么此操作将会创建一个新文档并插入数据库。如果匹配到文档,那么此操作将修改或者替换匹配到的一个或多个文档。

1.3示例集合

本页的例子在mongo shell中使用db.collection.find() 方法。在mongo shell中,如果没有将游标赋给一个var类型的变量,那么游标将会自动迭代20次以打印结果集中的前20个文档。

mongo shell中执行下面的语句,将数据灌入users 集合。

db.users.insertMany(

[

{

_id: 1,

name: "sue",

age: 19,

type: 1,

status: "P",

favorites: { artist: "Picasso", food: "pizza" },

finished: [ 17, 3 ],

badges: [ "blue", "black" ],

points: [

{ points: 85, bonus: 20 },

{ points: 85, bonus: 10 }

]

},

{

_id: 2,

name: "bob",

age: 42,

type: 1,

status: "A",

favorites: { artist: "Miro", food: "meringue" },

finished: [ 11, 25 ],

badges: [ "green" ],

points: [

{ points: 85, bonus: 20 },

{ points: 64, bonus: 12 }

]

},

{

_id: 3,

name: "ahn",

age: 22,

type: 2,

status: "A",

favorites: { artist: "Cassatt", food: "cake" },

finished: [ 6 ],

badges: [ "blue", "Picasso" ],

points: [

{ points: 81, bonus: 8 },

{ points: 55, bonus: 20 }

]

},

{

_id: 4,

name: "xi",

age: 34,

type: 2,

status: "D",

favorites: { artist: "Chagall", food: "chocolate" },

finished: [ 5, 11 ],

badges: [ "Picasso", "black" ],

points: [

{ points: 53, bonus: 15 },

{ points: 51, bonus: 15 }

]

},

{

_id: 5,

name: "xyz",

age: 23,

type: 2,

status: "D",

favorites: { artist: "Noguchi", food: "nougat" },

finished: [ 14, 6 ],

badges: [ "orange" ],

points: [

{ points: 71, bonus: 20 }

]

},

{

_id: 6,

name: "abc",

age: 43,

type: 1,

status: "A",

favorites: { food: "pizza", artist: "Picasso" },

finished: [ 18, 12 ],

badges: [ "black", "blue" ],

points: [

{ points: 78, bonus: 8 },

{ points: 57, bonus: 7 }

]

}

]

)

1.4 更新一个文档的指定字段

为了改变字段,MongoDB提供了更新操作符,例如,使用$set修改字段值。

更新文档的格式为:

{

<update operator>: { <field1>: <value1>, ... },

<update operator>: { <field2>: <value2>, ... },

...

}

有些更新操作符会在被更新字段不存在的情况下创建该字段,如 $set

db.collection.updateOne()

3.2版本新增

下面的例子演示使用db.collection.updateOne()方法和匹配条件favorites.artist等于“Picasso”,更新匹配出的多个文档中的第一个:

  • 使用操作符$set将字段favorites.food的值修改为“pie”并将字段的类型值改为3.
  • 使用操作符 $currentDate将字段lastModified 的值更改为当前时间。如果字段lastModified 不存在,$currentDate 会创建此字段。

db.users.updateOne(

{ "favorites.artist": "Picasso" },

{

$set: { "favorites.food": "pie", type: 3 },

$currentDate: { lastModified: true }

}

)

db.collection.updateMany()

3.2版本新增

下面的例子演示使用db.collection.updateMany()方法和匹配条件favorites.artist等于“Picasso”,更新匹配出的所有文档:

  • 使用操作符$set将字段favorites.food的值修改为“pie”并将字段的类型值改为3.
  • 使用操作符 $currentDate将字段lastModified 的值更改为当前时间。如果字段lastModified不存在,$currentDate会创建此字段。

db.users.updateMany(

{ "favorites.artist": "Picasso" },

{

$set: { "favorites.artist": "Pisanello", type: 3 },

$currentDate: { lastModified: true }

})

Db.collection.update()

下面的例子演示使用db.collection.updateOne()方法和匹配条件favorites.artist等于“Picasso”,更新匹配出的多个文档中的第一个:

  • 使用操作符$set将字段favorites.food的值修改为“pie”并将字段的类型值改为0.
  • 使用操作符 $currentDate将字段lastModified 的值更改为当前时间。如果字段lastModified 不存在,$currentDate 会创建此字段。

db.users.update(

{ "favorites.artist": "Pisanello" },

{

$set: { "favorites.food": "pizza", type: 0,  },

$currentDate: { lastModified: true }

})

使用db.collection.update()方法和multi: true 选项更新多个文档

db.users.update(

{ "favorites.artist": "Pisanello" },

{

$set: { "favorites.food": "pizza", type: 0,  },

$currentDate: { lastModified: true }

},

{ multi: true })

1.5 替换文档

为了替换一个文档中除_id字段以外的所有内容,将一个新文档作为db.collection.replaceOne()db.collection.update()的第二个参数进行传递。替换文档必须由<field> : <value>组成。

替换文档可以包含不同于原文档的字段。因为_id字段是不变的,所以替换文档中的_id字段可以省略,如果替换文档中包含_id字段,那么替换文档的

_id字段值必须与原文档相同。

db.collection.replaceOne

下面的例子演示了使用db.collection.replaceOne()方法和过滤条件条件为name 等于"abc" ,将集合users 中匹配到的第一个文档替换为一个新文档。

db.users.replaceOne(

{ name: "abc" },

{ name: "amy", age: 34, type: 2, status: "P", favorites: { "artist": "Dali", food: "donuts" } })

db.collection.update

下面的例子演示了使用db.collection.update()方法和过滤条件为name 等于"xyz" ,将集合users 中匹配到的第一个文档替换为一个新文档。

db.users.update(

{ name: "xyz" },

{ name: "mee", age: 25, type: 1, status: "A", favorites: { "artist": "Matisse", food: "mango" } })

其他方法

下面列举了删除文档的其他方法:

写确认

对于写确认,可以为写操作指定要求的确认级别,具体参见 Write Concern

2 删除文档

2.1 删除方法

MongoDB提供下列方法删除集合中的文档。


db.collection.remove()


删除使用指定过滤器匹配到的一个或全部文档


db.collection.deleteOne()


至多删除一个文档,即使使用指定过滤器匹配到多个文档。

3.2版本中新增


db.collection.deleteMany()


删除匹配到的所有文档。

3.2版本中新增

你可以使用准则、过滤器确定要删除的文档。这些过滤器与读操作所使用的过滤器具有相同的语法规则。

  • 查询过滤器文档使用<field>:<value>指定相等条件,筛选出所有字段<field>的值为<value>的文档:

    { <field1>: <value1>, ... }

  • 查询过滤器文档可以使用查询操作符指定匹配条件:

    { <field1>: { <operator1>: <value1> }, ... }

2.2 删除行为

索引

执行删除操作时,即使删除一个集合中的全部文档,也不会删除索引。

原子性

MongoDB中所有写操作在单文档级别具有原子性。

2.3示例集合

本页提供了在mongo shell中使用删除操作的例子。在mongo shell中执行下面语句,向集合users 中灌入数据。

注:

如果待插入文档的_id字段值与集合已有文档_id字段值相同,那么在插入数据前要先将集合删除(db.users.drop())。

db.users.insertMany(

[

{

_id: 1,

name: "sue",

age: 19,

type: 1,

status: "P",

favorites: { artist: "Picasso", food: "pizza" },

finished: [ 17, 3 ],

badges: [ "blue", "black" ],

points: [

{ points: 85, bonus: 20 },

{ points: 85, bonus: 10 }

]

},

{

_id: 2,

name: "bob",

age: 42,

type: 1,

status: "A",

favorites: { artist: "Miro", food: "meringue" },

finished: [ 11, 25 ],

badges: [ "green" ],

points: [

{ points: 85, bonus: 20 },

{ points: 64, bonus: 12 }

]

},

{

_id: 3,

name: "ahn",

age: 22,

type: 2,

status: "A",

favorites: { artist: "Cassatt", food: "cake" },

finished: [ 6 ],

badges: [ "blue", "red" ],

points: [

{ points: 81, bonus: 8 },

{ points: 55, bonus: 20 }

]

},

{

_id: 4,

name: "xi",

age: 34,

type: 2,

status: "D",

favorites: { artist: "Chagall", food: "chocolate" },

finished: [ 5, 11 ],

badges: [ "red", "black" ],

points: [

{ points: 53, bonus: 15 },

{ points: 51, bonus: 15 }

]

},

{

_id: 5,

name: "xyz",

age: 23,

type: 2,

status: "D",

favorites: { artist: "Noguchi", food: "nougat" },

finished: [ 14, 6 ],

badges: [ "orange" ],

points: [

{ points: 71, bonus: 20 }

]

},

{

_id: 6,

name: "abc",

age: 43,

type: 1,

status: "A",

favorites: { food: "pizza", artist: "Picasso" },

finished: [ 18, 12 ],

badges: [ "black", "blue" ],

points: [

{ points: 78, bonus: 8 },

{ points: 57, bonus: 7 }

]

}

])

2.4删除所有文档

为了删除全部文档,使用db.collection.deleteMany() 或db.collection.remove()方法并将空过滤器文档{}传给方法。

db.collection.deleteMany()

例如使用db.collection.deleteMany()方法删除users 集合中所有文档:

db.users.deleteMany({})

返回结果文档中包含操作状态:

{ "acknowledged" : true, "deletedCount" : 7 }

db.collection.remove()

或者使用db.collection.remove() 方法来删除所有文档:

db.users.remove({})

为了删除一个集合中的所有文档,db.collection.drop() 方法或许更高效;使用db.collection.drop() 方法删除集合中的所有文档及其索引,然后重新创建集合和索引。

3.5删除匹配到的所有文档

为了删除所有匹配到的文档,传递一个过滤器给db.collection.deleteMany() 或 db.collection.remove()方法。

db.collection.deleteMany()

例如,使用db.collection.deleteMany() 方法删除users 集合中status 字段值等于“A”的文档

db.users.deleteMany({ status : "A" })

返回结果:

{ "acknowledged" : true, "deletedCount" : 3 }

db.collection.remove()

或者使用db.collection.remove()方法删除users 集合中status 字段值等于“P”的文档

db.users.remove( { status : "P" } )

对于大的删除操作,先将想保留的文档拷贝到新的集合中,然后使用db.collection.drop() 将原来的集合删除,这种方法或许更高效。

2.6 仅删除匹配到的文档中的一个

即使匹配到了多个文档,也只删除其中的一个,使用db.collection.deleteOne() 方法,或者使用db.collection.remove()方法和使用<justOne>参数并将其设置为true或1 。

db.collection.deleteOne()

例如,使用db.collection.deleteOne() 删除集合中status字段值为“D”的文档中的第一个:

db.users.deleteOne( { status: "D" } )

db.collection.remove()

或者使用db.collection.remove()方法删除users 集合中status 字段值等于“D”的文档中的第一个:

db.users.remove( { status: "D" }, 1)

其他方法:

  • db.collection.findOneAndDelete():该方法提供了sort选项,sort选项可以删除按指定顺序排序的文档中的第一个。
  • db.collection.findOneAndModify():该方法提供了sort选项,sort选项可以删除按指定顺序排序的文档中的第一个。
  • db.collection.bulkWrite()

2.7 写确认

对于写确认,可以为写操作指定需要的确认级别,具体参见 Write Concern

3 批量写入操作

3.1 概要

MongoDB客户端具有执行批量写的能力。批量写操作只会影响一个集合。MongoDB由应用程序决定可接受的批量写操作安全级别。

3.2版本中新增:

db.collection.bulkWrite()方法提供了批量插入、更新、删除。使用db.collection.insertMany()方法也可批量插入。

3.2排序与非排序操作

可以批量写入一批已排序或未排序的文档。

对于有序的操作列表,MongoDB 按顺序执行操作。如果在执行一个写操作时发生错误,MongoDB 将会返回而不处理列表中剩下的操作。

对于无序的操作列表,MongoDB 并行地执行操作,但这种行为是无保障的。如果在执行一个写操作时发生错误,MongoDB 将会继续执行列表中剩下的操作。

MongoDB处理有序列表的速度比处理无序列表的速度要慢,因为处理有序列表时,每一个操作都要等待前一个操作执行完毕。

bulkWrite()方法默认依序执行操作。在选项文档中设置ordered : false,可以按无序方式执行。

3.3 bulkWrite()

bulkWrite()支持下列写操作:

每个写操作作为数组中的一个文档被传递给bulkWrite() 。

例如,下面执行多个写操作:

集合characters包含下面的文档:

{ "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },

{ "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },

{ "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }

下面bulkWrite() 方法执行多个操作:

try {

db.characters.bulkWrite(

[

{ insertOne :

{

"document" :

{

"_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4

}

}

},

{ insertOne :

{

"document" :

{

"_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3

}

}

},

{ updateOne :

{

"filter" : { "char" : "Eldon" },

"update" : { $set : { "status" : "Critical Injury" } }

}

},

{ deleteOne :

{ "filter" : { "char" : "Brisbane"} }

},

{ replaceOne :

{

"filter" : { "char" : "Meldane" },

"replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }

}

}

]

);}catch (e) {

print(e);}

操作返回结果为:

{

"acknowledged" : true,

"deletedCount" : 1,

"insertedCount" : 2,

"matchedCount" : 2,

"upsertedCount" : 0,

"insertedIds" : {

"0" : 4,

"1" : 5

},

"upsertedIds" : {

}}

3.4文档批量插入一个分片集策略

大块插入操作,包括初始数据插入和常规数据导入,都能影响分片集群的性能。对于大块的插入操作,考虑下面的策略:

集合预裂(Pre-Split the Collection)

如果分片集合是空的,那么集合仅有一个初始块,这一块驻留在一片中。然后,MongoDB必须花时间来接收数据,创建分片,并将多个块分布到可用的片上。为了避免降低性能,你可以提前对一个集合分片。

无序写入

为了改进写入分片集群的性能,将 bulkWrite()方法的选项参数ordered 设置为false。mongos 将会试着同时写多片。

避免单调调节

如果插入文档的同时片键单调递增,所有已插入的数据都会跑到集合的最后一块,这总在一片上发生。因此集群的插入容量永远都不会超过一片的插入容量。

如果插入的量比一片所能处理的最大量还大,并且不能避免片键随着插入操作而增大,那么考虑按下面的策略修改你的应用程序:

  • 修改片键的二进制比特数,这保留了信息,同时也避免了插入顺序与增加值序列关联。
  • 交换第一个和最后一个16比特的词来调整插入。

例如,下面的C++代码,交换BSON ObjectIds头与尾16比特单词,使其不再单调增加。

using namespace mongo;

OID make_an_id() {

OID x = OID::gen();

const unsigned char *p = x.getData();

swap( (unsigned short&) p[0], (unsigned short&) p[10] );

return x;

}

void foo() {

// create an object

BSONObj o = BSON( "_id" << make_an_id() << "x" << 3 << "name" << "jane" );

// now we may insert o into a sharded collection

}

4  SQL与MongoDB映射图

4.1术语和概念

下表展示了SQL与MongoDB的术语和概念对应关系


SQL Terms/Concepts


MongoDB Terms/Concepts


database(数据库)


database(数据库)


table(表)


collection(集合)


row(行)


document or BSON document(文档或BSON文档)


column(列)


field(字段)


index(索引)


index(索引)


table joins(表链接)


embedded documents and linking(嵌入式文档和连接)


primary key(主键)

指定唯一的一列或几列做主键


primary key(主键)

在MongoDB中,主键被自动设置为_id字段。


aggregation (聚集操作)(例如group by)


aggregation pipeline(聚集管道)

4.2可执行程序

下面的表格列举了目前数据库可执行程序与MongoDB可执行程序的对照。

此表并未列举全。


 


MongoDB


MySQL


Oracle


Informix


DB2


数据库服务器


mongod


mysqld


oracle


IDS


DB2 Server


数据库客户端


mongo


mysql


sqlplus


DB-Access


DB2 Client

4.3例子

下面列出了SQL语句与MongoDB语句的对应关系。假设有如下的条件:

SQL语句中的表名为users。

MongoDB 中集合的名称为users并且包含下面的文档模型:

{

_id: ObjectId("509a8fb2f3f4948bd2f983a0"),

user_id: "abc123",

age: 55,

status: ‘A‘

}

创建和更改

下面展示了表级操作对应关系。


SQL模式语句


MongoDB模式语句


CREATE TABLE users (

id MEDIUMINT NOT NULL

AUTO_INCREMENT,

user_id Varchar(30),

age Number,

status char(1),

PRIMARY KEY (id)

)


第一次执行insert() 操作会隐式创建集合。

如果没有指定_id字段,主键_id被自动添加.

db.users.insert(

{    user_id: "abc123",    age: 55,    status: "A" }

)

也可显示创建集合:

db.createCollection("users")


ALTER TABLE users

ADD join_date DATETIME


集合不会描述和强制文档的结构;在集合这一级文档结构的改变

但在文档级, 可使用update()操作和 $set操作符向现有文档中添加字段。

db.users.update(

{ },

{ $set: { join_date: new Date() } },

{ multi: true }

)


ALTER TABLE users

DROP COLUMN join_date


集合不会描述和强制文档的结构;在集合这一级文档结构的改变

但在文档级, 可使用update()操作和  $unset操作符删除文档中的字段。

db.users.update(

{ },

{ $unset: { join_date: "" } },       { multi: true }

)


CREATE INDEX idx_user_id_asc

ON users(user_id)


db.users.createIndex( { user_id: 1 } )


CREATE INDEX

idx_user_id_asc_age_desc

ON users(user_id, age DESC)


db.users.createIndex( { user_id: 1, age: -1 } )


DROP TABLE users


db.users.drop()

 

插入

下表展示了插入操作的对应关系


SQL插入语句


MongoDB insert() 语句


INSERT INTO users(user_id,age,status)

VALUES ("bcd001",45,"A")


db.users.insert(   { user_id: "bcd001", age: 45, status: "A" })

查询

下表展示了查询操作的对应关系

注:

find() 方法的执行结果返回文档中总是包含_id字段,除非通过投影器(projection)排除此字段。考虑到这一点,下面的SQL语句可能包含_id字段,即使在相应的find()方法中不包含_id字段。


SQL查询语句


MongoDB find()语句


SELECT *FROM users


db.users.find()


SELECT id,

user_id,

status

FROM users


db.users.find(    { },    { user_id: 1, status: 1 })


SELECT user_id, statusFROM users


db.users.find(    { },    { user_id: 1, status: 1, _id: 0 })


SELECT *FROM usersWHERE status = "A"


db.users.find(    { status: "A" })


SELECT user_id, statusFROM usersWHERE status = "A"


db.users.find(    { status: "A" },    { user_id: 1, status: 1, _id: 0 })


SELECT *FROM usersWHERE status != "A"


db.users.find(    { status: { $ne: "A" } })


SELECT *FROM usersWHERE status = "A"AND age = 50


db.users.find(    { status: "A",      age: 50 })


SELECT *FROM usersWHERE status = "A"OR age = 50


db.users.find(    { $or: [ { status: "A" } ,             { age: 50 } ] })


SELECT *FROM usersWHERE age > 25


db.users.find(    { age: { $gt: 25 } })


SELECT *FROM usersWHERE age < 25


db.users.find(   { age: { $lt: 25 } })


SELECT *FROM usersWHERE age > 25AND   age <= 50


db.users.find(   { age: { $gt: 25, $lte: 50 } })


SELECT *FROM usersWHERE user_id like "%bc%"


db.users.find( { user_id: /bc/ } )


SELECT *FROM usersWHERE user_id like "bc%"


db.users.find( { user_id: /^bc/ } )


SELECT *FROM usersWHERE status = "A"ORDER BY user_id ASC


db.users.find( { status: "A" } ).sort( { user_id: 1 } )


SELECT *FROM usersWHERE status = "A"ORDER BY user_id DESC


db.users.find( { status: "A" } ).sort( { user_id: -1 } )


SELECT COUNT(*)FROM users


db.users.count()

db.users.find().count()


SELECT COUNT(user_id)FROM users


db.users.count( { user_id: { $exists: true } } )

db.users.find( { user_id: { $exists: true } } ).count()


SELECT COUNT(*)FROM usersWHERE age > 30


db.users.count( { age: { $gt: 30 } } )

db.users.find( { age: { $gt: 30 } } ).count()


SELECT DISTINCT(status)FROM users


db.users.distinct( "status" )


SELECT *FROM usersLIMIT 1


db.users.findOne()

db.users.find().limit(1)


SELECT *FROM usersLIMIT 5SKIP 10


db.users.find().limit(5).skip(10)


EXPLAIN SELECT *FROM usersWHERE status = "A"


db.users.find( { status: "A" } ).explain()

更新记录

下表展示了更新操作的对应关系


SQL更新语句


MongoDB update()语句


UPDATE usersSET status = "C"WHERE age > 25


db.users.update(

{ age: { $gt: 25 } },   { $set: { status: "C" } },   { multi: true }

)


UPDATE usersSET age = age + 3WHERE status = "A"


db.users.update(

{ status: "A" } ,   { $inc: { age: 3 } },   { multi: true }

)

删除记录

下表展示了更删除操作的对应关系


SQL更新语句


MongoDB update()语句


DELETE FROM usersWHERE status = "D"


db.users.remove( { status: "D" } )


DELETE FROM users


db.users.remove({})

5 读关注

3.2版本新增

MongoDB3.2为副本集和副本集分片引入了readConcern 查询选项。默认地,执在行查询操作时,MongoDB使用“local”读关注来返回可用的MongoDB实例上的最新数据。即使数据没有被保存在副本集主成员中并且可能已经回滚。

存储引擎和驱动支持

对于WiredTiger存储引擎,readConcern选项允许客户端选择读隔离级别。你可以指定“majority”读关注来读取已经写入副本集主成员的数据并且数据不能回滚。

对于MMAPv1存储引擎,只能将readConcern 指定为“local”。

提示:

serverStatus 命令返回字段storageEngine.supportsCommittedReads指明存储引擎是否支持“majority”读关注。

读关注级别

默认地,MongoDB readConcern被配置为“local”,这不保证读到的数据是不被回滚。

如果指定readConcern 为"majority" 读取已经写入副本集主成员的数据,这样的数据不会回滚。


级别


描述


"local"


默认级别。查询返回MongoDB实例中的最新的数据。不保证数据被写入副本集主成员。


"majority"


查询操作返回MongoDB实例中写入副本集主成员的最新数据拷贝。

为了使用 "majority"级的读关注,必须使用WiredTiger 存储引擎并且使用enableMajorityReadConcern命令行选项(或者使用replication.enableMajorityReadConcern来设置配置文件)。

只有使用副本集选举协议版本1(protocol version 1)的副本集才支持“majority”,副本集使用版本0(protocol version 0)则不支持“majority”。

为了让一个线程读取它自己写入的数据,在副本集主成员上使用 "majority"级读关注和“majority”级写关注。

除了读关注级别,一个节点上的最新数据可能不是系统中的最新数据。

readConcern 选项

使用readConcern选项来指定读关注级别:

readConcern: { level: <"majority"|"local"> }

对于level字段,指定值为"majority" 或 "local"。

readConcern 选项在下列操作中也可用:

mongo shell中的db.collection.find()方法指定读关注,使用cursor.readConcern()方法。

6 写关注

写关注描述了来自于MongoDB的对独立的mongod 或者副本集或者分片集群执行写操作的确认级别。对于一个分片集群,mongos实例会将写关注传递给每一片。

3.2版本中的变化是:对于使用protocolVersion: 1 并启用journal的副本集 。

  • w: "majority"表明 j: true
  • 即使 j 选项被设置为向主成员写,当数据已经写入第二成员(Secondary members)各自的磁盘后,第二成员仍会确认复制写操作。

2.6版本的变化:新的协议完善了写操作的写关注并消除了调用getLastError 的需求。之前的版本为了指定写关注需要在写操作后立即调用getLastError 。

写关注规范

写关注文档包括下列字段:

{ w: <value>, j: <boolean>, wtimeout: <number> }

  • w选项请求确认写操作已经传播到了指定序号的mongod实例上或指定标记的mongod 实例上。
  • j 选项请求确认写操作已经写入日志。
  • wtimeout 指定了时间限制,防止写操作无限期的阻塞进程。

w 选项

w选项请求确认写操作已经传播到了指定序号的mongod实例上或指定标记的mongod 实例上。

使用w选项,w: <value>是可用的。

注:

除非j:true,否则在内存中应用写操作以后,独立的mongod实例和副本集主成员会设置写操作确认。

3.2:版本中的变化:对于使用protocolVersion: 1的副本集,不管j 选项如何配置,数据写入第二成员(Secondary members)各自的磁盘后,第二成员确认复制写操作。



描述


<number>


请求确认写操作已经传播到了指定序号的mongod实例。例如:

w: 1

请求确认写操作已经传播到了独立的mongod 或者副本集主成员。 w: 1是MongoDB默认的。

w: 0

不对写操作请求确认,然而,设置为w: 0 ,返回信息或许会包括应用程序中的socket 异常和网络错误。

如果指定w: 0 但是 j: true,那么j: true确保了来自独立的mongod 或者副本集主成员的确认请求。

将number设置为大于1仅对来自副本集指定成员(包括主成员)的确认请求有效。


"majority"


3.2版本中新增

写操作确认请求传播到选中节点的大多数上,包括主成员,并且已被写入各自的磁盘日志。

对于副本集使用了 protocolVersion: 1, w: "majority" 表明j: true。因此不像w: <number>,使用w: "majority"主副本集也会在写确认之前写磁盘日志。

将写确认设置为w:"majority"的写操作返回客户端后,客户端会以读关注设置为"majority" 的方式读取结果。


<tag set>


写操作确认请求传播到了指定标签的副本集成员。

J选项请求确认写操作被记录到了日志。


j


请求确认mongod实例将写操作记录到了日志,其中指定w: <value>。仅靠j: true不能保证写操作不会回滚,由于副本集主成员故障转移。

3.2版本中的变化:设置j: true,MongoDB仅当请求成员将写操作记录到了日志后返回结果。在一个复制集内的写关注,之前的版本中j: true,请求副本集主成员写日志,而不管w: <value>如何设置。

如果日志可用的话,对于使用protocolVersion: 1的副本集,w: "majority" 表明 j: true。默认地写日志是可用的。

2.6版本中的变化,对于mongod 或者运行--nojournal选项的mongos ,指定j: true的写关注会产生错误 。之前的版本忽略j: true。

wtimeout

对于写关注,选项指定了以毫秒为单位的时间限制,wtimeout 是唯一的可将w值设置为大于1的。

如果超过指定的时间限制,wtimeout 会引起写操作返回包含错误,即使请求的写关注最终会成功。当写操作返回时,在写关注超过wtimeout时间限制以前,MongoDB 不会取消对成功数据的修改。

如果你没有为写关注指定wtimeout 选项,指定级别的写关注不可实现,写操作将会无限期阻塞。指定wtimeout 为0等价于无wtimeout 选项的写关注。

-----------------------------------------------------------------------------------------

转载与引用请注明出处。

时间仓促,水平有限,如有不当之处,欢迎指正。

时间: 2024-11-03 01:30:21

【翻译】MongoDB指南/CRUD操作(二)的相关文章

【翻译】MongoDB指南/CRUD操作(三)

[原文地址]https://docs.mongodb.com/manual/ CRUD操作(三) 主要内容: 原子性和事务(Atomicity and Transactions),读隔离.一致性和新近性,分布式查询(Distributed Queries),分布式写操作,模拟两阶段任务提交,在副本集中执行配额读取 1 原子性和事务(Atomicity and Transactions) 在MongoDB中,写操作在单文档级别具有原子性,即使修改一个文档中的多个嵌入式文档也是如此. 当一个写操作修

【翻译】MongoDB指南/CRUD操作(一)

[原文地址]https://docs.mongodb.com/manual/ MongoDB CRUD操作(一) 主要内容:CRUD操作简介,插入文档,查询文档. CRUD操作包括创建.读取.更新和删除文档. 创建操作 执行创建或者插入操作可向集合中添加文档.如果集合不存在,插入操作会创建此集合. MongoDB提供下列方法向集合中插入文档: db.collection.insert() db.collection.insertOne()  3.2版本新增 db.collection.inser

mongodb的CRUD操作二查询

---恢复内容开始--- 查询才是我们用的最多最多的 find() 查询所有的行 指定一个关键字的查询 那么我想看这个列的所有行 前面的{}是代表了我没有加任何的条件 这里是代表是我要找uname是LY的行的deptnolie.前面的_id:0是代表我不想显示_id这个列 这里就是代表了我想要看这些列的所有行可以对比一下 过滤一些列的写法xxx:0就可以了 去重 distinct("列名") 这样我就可以把这列的值去重了 分页查询 加了条件的限制查询 跳开前几行: 从第3行开始到第6行

Ruby操作MongoDB(进阶)-CRUD操作

MongDB数据库的使用离不开CRUD操作.什么是CRUD,就是创建文档,读取文档信息,更新文档和删除文档. key-value键值对标记 在MongoDB的Ruby驱动中,Key_value键值多次出现.而且有时会出现语法上的巧合,这取决于在使用的Ruby版本中如何申明. 在文档创建步骤中,1.9及之后版本支持以下语法: document={name:"Tom",age:20}. 但是如果你使用的是2.2或者更高的版本,你可以用双引号将你的key包起来.如: document={&q

MongoDB的CRUD操作

1. 前言 在上一篇文章中,我们介绍了MongoDB.现在,我们来看下如何在MongoDB中进行常规的CRUD操作.毕竟,作为一个存储系统,它的基本功能就是对数据进行增删改查操作. MongoDB中的增删改查操作,不同于我们熟悉的关系数据库中的操作.在关系数据库中,比如MySQL,我们通常使用SQL语句对数据库进行增(INSERT)删(DELETE)改(UPDATE)查(SELECT).MongoDB在对数据进行操作过程中,使用的是Document进行数据操作.在对数据库进行操作的时候,使用Do

MongoDB对图片进行CRUD操作——与JAVA结合

上几篇博客简单对MongoDB进行了简单介绍和如何安装,以及在dos下是如何操作MongoDB和在安装MongoDB中,出现了什么错误,是如何解决的.当然这些都还不够,我们还要用到实际当中去.我用MyEclipse+JDK1.7做了一个简单的demo,来展示下MongoDB怎么运用到实际中去. MongoDB作为一个NoSql数据库的代表,存取多媒体数据,应该是强项吧?那么,在MongoDB中是如何对图片进行CRUD操作的. 上几篇博客中已经提到,MongoDB的文档结构是BSON格式,BSON

MongoDB的CRUD操作(java Util )

1.保存插入操作: public static synchronized String insert(DBObject record) { DBCollection col = MongoDB.getDBCollection(TABLE_NAME); record.put("time", new Date().getTime()); WriteResult result = col.insert(record); //当前插入表的_id return record.get("

mongodb的CRUD操作三

聚合操作 count()统计行数 计算总计 sum aggregate是聚合的操作符,然后分组,然后再sum

Mongodb的安装与CRUD操作

What is Mongodb ?         Mongo DB是一款开源的非关系型数据库(NoSql)其文档模型自由灵活,可以让你在开发过程中畅顺无比.对于大数据量.高并发.弱事务的互联网应用,MongoDB可以应对自如.MongoDB内置的水平扩展机制提供了从百万到十亿级别的数据量处理能力,完全可以满足Web2.0和移动互联网的数据存储需求,其开箱即用的特性也大大降低了中小型网站的运维成本. 安装Mongodb 来到mongodb官网http://www.mongodb.org/可以在这