mongo基础之 CRUD操作(3)

创建create

常用方法

    db.collection.save(obj)

    db.collection.insert(obj)
    db.collection.insertOne( obj, <optional params> ) - insert a document, optional parameters are: w, wtimeout, j
    db.collection.insertMany( [objects], <optional params> ) - insert multiple documents, optional parameters are: w, wtimeout, j

Insert和Save的区别是:

如果插入的集合的“_id”值,在集合中已经存在,用Insert执行插入操作回报异常,已经存在"_id"的键。用Save如果系统中没有相同的"_id"就执行插入操作,有的话就执行覆盖掉原来的值。相当于修改操作。我这里就不做演示了。

插入示例

1 插入单个文档,返回一个包含新插入文档的id字段值的文档。

> db.inventory.insertOne({ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } })

{"acknowledged" : true,"insertedId" : ObjectId("5c8f5d9ae161d7c69f0cb263")}

>db.inventory.insertOne({ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } },{ writeConcern: { w: "majority", j:true,wtimeout: 5000 }})

{ "acknowledged" : true,"insertedId" : ObjectId("5dc390dae71e53d454d8a1b7")}

2  插入多个文档

> db.inventory.insertMany([

     { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },

       { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },

       { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }

 ])

{

"acknowledged" : true,

"insertedIds" : [

ObjectId("5c8f5e8ee161d7c69f0cb264"),

ObjectId("5c8f5e8ee161d7c69f0cb265"),

ObjectId("5c8f5e8ee161d7c69f0cb266")

]

}

3 insertMany 带着writeconcern选项

db.inventory.insertMany([

     { item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },

       { item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },

       { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }

 ],{ writeConcern: { w: "majority", j:true,wtimeout: 5000 }})

返回结果同上。

mongoDB是怎样插入文档的

  • 创建集合
    如果集合当前不存在,就创建集合。
  • _id 字段
    在MongoDB中,存储在集合中的每个文档都需要一个唯一的ID字段作为主键。如果插入的文档省略了_id字段,MongoDB驱动程序会自动为_id字段生成一个objectid
  • 原子性
    MongoDB中的所有写操作都是单文档级别的原子操作,如果在批量插入的过程中有一个文档插入失败,那么在这个文档之前的所有文档都会成功插入到集合中,而这个文档以及之后的所有文档全部插入失败。如果希望batchInsert忽略错误并且继续执行后续插入,可以使用continueOnError选项。shell并不支持这个选项,但所有的驱动程序都支持
  • 写确认
    您可以指定MongoDB为写操作请求的确认级别https://blog.csdn.net/xiaoliuliu2050/article/details/102951111

注意:

插入性能:200W的数据,在之前没有排序就直接插入,耗时4小时多,现在,做了排序,插入只需要5分钟。排序对于单机版本的MongoDB性能更佳,避免了随机插入引发的频繁随机IO。

查询read

查询集合中的文档:

  • db.collection.find()

您可以指定查询筛选器或条件,以标识要返回的文档。
在这里插入图片描述

准备数据

db.inventory.insertMany([

   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },

   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },

   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },

   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },

   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }

]);

查询

  • 查询集合中的所有文档

> db.inventory.find( {} )

例子:从集合中选择状态为“d”的所有文档:

>db.inventory.find( { status: "D" } )

  • 使用查询运算符指定条件

>db.inventory.find( { status: { $in: [ "A", "D" ] } } )

备注:$or $in有相同的作用,但是请尽量使用 $in

  • 指定and条件
    复合查询可以为集合文档中的多个字段指定条件

>db.inventory.find( { status: "A", qty: { $lt: 30 } } )

  • 指定or条件

>db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

使用比较运算符的查询受类型括号限制。

  • 同时指定and和or条件

>db.inventory.find( {

     status: "A",

     $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]

} )

相当于SQL中的

SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")

mongodb支持正则表达式$ regex查询来执行字符串模式匹配。

使用$regex时,有以下几种用法:

1

2

3

{ <field>: { $regex: /pattern/, $options: '<options>' } }

{ <field>: { $regex: 'pattern', $options: '<options>' } }

{ <field>: { $regex: /pattern/<options> } }

option参数的含义:

选项含义使用要求
i大小写不敏感
m

查询匹配中使用了锚,例如^(代表开头)和$(代表结尾),以及匹配\n后的字符串

x

忽视所有空白字符

要求$regex与$option合用
s允许点字符(.)匹配所有的字符,包括换行符。要求$regex与$option合用

以下是几种用法

 和in 配合使用,值为正则表达式

{ name: { $in: [ /^acme/i, /^ack/ ] } } 

和regex 配合 值为正则表达式

{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } } 

 

和regex 配合 值为正则表达式,并且添加$options 选项

{ name: { $regex: /acme.*corp/, $options: 'i', $nin: [ 'acmeblahcorp' ] } }  

和regex 配合 值为字符串 并且添加$options 选项

{ name: { $regex: 'acme.*corp', $options: 'i', $nin: [ 'acmeblahcorp' ] } }

Warning:警告

1.虽然/^a/,/^a.*/和/^a.*$/匹配等效字符串,但它们的性能是不一样的。如果有对应的索引,所有这些表达式就都使用索引;不过,/^a.*/和/^a.*$/较慢。 这是因为/^a/可以在匹配前缀后停止扫描。

2.不区分大小写的正则表达式查询通常不能使用索引,$regex无法使用不区分大小写的索引。

java api:

//完全匹配
Pattern pattern = Pattern.compile("^王$", Pattern.CASE_INSENSITIVE);
//右匹配
Pattern pattern = Pattern.compile("^.*王$", Pattern.CASE_INSENSITIVE);
//左匹配
Pattern pattern = Pattern.compile("^王.*$", Pattern.CASE_INSENSITIVE);
//模糊匹配
Pattern pattern = Pattern.compile("^.*王.*$", Pattern.CASE_INSENSITIVE);
Query query = Query.query(Criteria.where(fieldName).regex(pattern));  
List<SimpleUserInfo> users = mongoTemplate.find(query, SimpleUserInfo.class, classname);
 

查询去重后的某列数据

>db.inventory.distinct("item");

查询指定列name、age数据

>db.userInfo.find({}, {name: 1, age: 1});

按照年龄排序

>升序:db.userInfo.find().sort({age: 1});

>降序:db.userInfo.find().sort({age: -1});

查询前5条数据

>db.userInfo.find().limit(5);

查询10条以后的数据

>db.userInfo.find().skip(10);

or与 查询

>db.userInfo.find({$or: [{age: 22}, {age: 25}]});

查询某个结果集的记录条数

>db.userInfo.find({age: {$gte: 25}}).count();

查询存在sex列的文档

>db.userInfo.find({sex: {$exists: true}})

查询嵌入/嵌套文档

>db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )  //要求条件完全匹配,包括顺序

.标记可以访问嵌套文档中的某个字段“field.nestedField

> db.inventory.find( { "size.uom": "in" } )    //查询inventory集合中size嵌套字段uom值为in的文档

> db.inventory.find( {"size.h":{$lt:15}})  //查询inventory集合中size嵌套字段h值比15小的文档

  • 和条件

>db.inventory.find( { "size.h": { $lt: 15 }, "size.uom": "in", status: "D" } )  //查询inventory集合中size嵌套字段h值比15小,uom值为in, status="D"的文档

光标

  • db.collection.find()方法将光标返回到匹配的文档。

准备数据查询数组

db.inventory.insertMany([
   { item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },
   { item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] },
   { item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },
   { item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },
   { item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }
]);
查找tags字段 是  ["red", "blank"]的文档
db.inventory.find( { tags: ["red", "blank"] } )
查找tags字段 包括red 和blank 的文档。
db.inventory.find( { tags: { $all: ["red", "blank"] } } )
查找tags中包含red的文档
db.inventory.find( { tags: "red" } )

查找tags 中不包含red 的文档

db.inventory.find( { tags: {$ne:"red"} } )


查找tags中包含red或者plain的文档
db.inventory.find( { "tags":{$in:["red","plain"]}} )
查找dim_cm字段中至少有一个大于25 的文档
db.inventory.find( { dim_cm: { $gt: 25 } } )

查找dim_cm字段中至少有一个大于15 并且至少有一个小于20的文档

db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )

查找dim_cm字段中至少有一个元素,同时满足大于22小于30 的条件。

db.inventory.find( { dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } } )


查找dim_cm字段中第一个元素大于的25的文档
db.inventory.find( { "dim_cm.1": { $gt: 25 } } )
查找tags数组长度等于3的文档
db.inventory.find( { "tags": { $size: 3 } } )

嵌套数组查询

db.inventory.insertMany( [
   { item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] },
   { item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] },
   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] },
   { item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] },
   { item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
]);

查询instock数组中某个元素等于{ warehouse: "A", qty: 5 }的文档

db.inventory.find( { "instock": { warehouse: "A", qty: 5 } } )


这个查询会返回空,因为没有匹配的元素
db.inventory.find( { "instock": { qty: 5, warehouse: "A" } } )

查询instock数组中 至少有一个元素的qty字段值小于20的文档

db.inventory.find( { 'instock.qty': { $lte: 20 } } )

查找instock数组的第一个元素的qty 的值小于等于20 的文档

db.inventory.find( { 'instock.0.qty': { $lte: 20 } } )

查找instock数组中至少有一个元素的qty=5 同时 warehouse=A

db.inventory.find( { "instock": { $elemMatch: { qty: 5, warehouse: "A" } } } )

查找instock数组中至少有一个元素的qty 大于10 小于20 同时 warehouse=A

db.inventory.find( { "instock": { $elemMatch: { qty: { $gt: 10, $lte: 20 } ,warehouse:"C"} } } )

查找instock数组中的元素里   至少有一个qty=5 ,至少有一个warehouse=A

db.inventory.find( { "instock.qty": 5, "instock.warehouse": "A" } )
 

  • Projection Operators
    • $(projection)
      功能:对array取下标。
      用法:db.collection.find( { <array.field>: <value> ...}, { "<array>.$": 1 } )
      例子:db.students.find( { grades: { $gte: 85 } }, { "grades.$": 1 } )
      例子效果:将选中文档中首个大于等于85的数返回。
      注:不能暴力使用多个array,提倡用$eleMatch。
      
    • $elemMatch(projection)
      功能:用于数组中的元素匹配,可用于find的第2个参数。
      用法:
      例子:db.schools.find( { zipcode: "63109" }, { students: { $elemMatch: { school: 102, age: { $gt: 10} } } } )
      例子效果:第2个参数是决定要返回的field的。
      注:看官网吧。
      
    • $meta
      功能:取出$text匹配的文档分数,看text了解score的概念就懂了。
      用法:{ $meta: <metaDataKeyword> }
      例子:db.collection.find( {$text: { $search: "coffee bake" } }, { score: { $meta: "textScore" } })
      例子效果:cofee bake两个单词的匹配工作会使得每个文档得到一个分数,$meta调出这个分数。
      注:要配合$text来使用,仅用于字符串搜索。
      
      参考索引 https://blog.csdn.net/xiaoliuliu2050/article/details/102912938
    • $slice(projection)
      功能:在查询中将数组进行切片。
      用法:{ <array>: {$slice: <count-expression> } }
      例子:db.posts.find( {_id:1}, { comments: { $slice: [23, 5] } } )
      例子效果:显示id=1的整个文档,但其中comments数组仅显示从第24开始的5个元素。
      注:<count-expression>有多种方式:<n>表前n个、<-n>表后n个、<[begin, n]>从下标begin开始的n个、<[-begin, n]>忽略掉后begin个再取后n个。
      

更新操作update

更新操作修改集合中的现有文档:

update

1    db.inventory.update( query, object[, upsert_bool, multi_bool] ) - instead of two flags, you can pass an object with fields: upsert, multi   注意第二个参数是对象,也就是想要的结果
2    db.inventory.updateOne( filter, update, <optional params> ) - update the first matching document, optional parameters are: upsert, w, wtimeout, j        
3   db.inventory.updateMany( filter, update, <optional params> ) - update all matching documents, optional parameters are: upsert, w, wtimeout, j

save

4 db.<collection>.save(obj)  适合已有完整要入库的文档的情况,并且数据不多。

find-update

db.collection.findAndModify({
    query: <document>,
    sort: <document>,//如果查询条件返回多个,则排序获取第一个
    remove: <boolean>,//是否删除
    update: <document>,// 和updateOne方法一样的参数
    new: <boolean>,//如果是true,返回修改后的文档
    fields: <document>,//指定返回字段
    upsert: <boolean>,//如果查询为空,是否插入
    bypassDocumentValidation: <boolean>,//直接通过文档校验
    writeConcern: <document>,
    collation: <document>
});

找到一个文档并更新或者删除   适合需要返回结果数据的情况,效率比直接更新要低。

6  db.collection.findOneAndUpdate( filter, update, <optional params> ) 找到并更新  适合需要返回结果数据的情况,效率比直接更新要低

replace

7 db.<collection>.replaceOne( filter, replacement, <optional params> )  和update 方法类似。

find-replace

8 db.collection.findOneAndReplace( filter, replacement, <optional params> )

找到并替换  适合需要返回结果数据的情况,效率比直接替换要低。
 

方法差异对比
1 前三种是由于历史原因产生的,实际上:

  • updateMany = update + {multi: true}
  • updateOne = update 或 update + {multi: false}

因为update本身的意义不够清楚,所以3.0以后才出现了updateManyupdateOne两个替代方法。这个方法没多少要说的,唯一要注意的就是,如果用update方法的话,不要忘记操作符($set$inc等等),不然……
updateManyupdateOne则没有这个问题,缺了操作符会直接报错。


2 update三兄弟和findAndModify比较

update只是更新操作,而findAndModify可以在找到结果后选择执行更新还是删除操作。说白了功能上findAndModify=updateOne+removeOne。注意它只能对单个文档进行操作。

无论更新还是删除,(『找到』『更新』)或(『找到』『删除』)都是原子性的,这点findAndModifyupdateOne/removeOne没有任何区别。区别只在于findAndModify在完成动作之后还可以选择把更新/删除之前或之后的文档返回给你。如果没有这个操作,那就必须先findupdate或者先updatefind,无论怎么做,都不能保证中间不被其他操作捷足先登。因此findAndModify在某些场景下是必要的,比如使用$inc生成递增序列(注意生成递增序列做ID不是个好想法,我在这个问题中做过解释)
因为findAndModify只针对单个文档,那么如果条件能找到多个文档怎么办?sort就用在这种场景下。

3 update和save

save实际上是一种特殊的update,即不带操作符的update。通俗地说叫『替换』。替换,代表你已经有这个文档完整的样子,即代表你已经把整个文档从数据库中读出来,在内存中进行了修改,然后完整替换回去。你并不能保证数据在被你读出来到写回去期间是否有别人已经改了数据库中的记录,这就是第一个风险,save操作存在潜在的可能性会覆盖掉别人更新过的数据。save还带来一个额外的副作用,因为整个文档都保存进去了,意味着整个文档都会进入oplog,这会显著增加oplog的使用速度。因此过度使用save常常还会造成oplog不够用,需要很大的oplog才能足够保存24小时的信息

在MongoDB中,更新操作以单个集合为目标。MongoDB中的所有写操作都是单文档级别的原子操作

使用update修改项时经常会遇到下面坑,先准备些数据。

var workmate1={
    name:'zyb',
    age:23,
    sex:1,
    job:'前端',
    skill:{
        skillOne:'HTML+CSS',
        SkillTwo:'JavaScript',
        SkillThree:'NODE'
    },
    regeditTime:new Date()
}
var workmate2={
    name:'zl',
    age:24,
    sex:1,
    job:'JAVA后端',
    skill:{
        skillOne:'HTML+CSS',
        SkillTwo:'J2EE',
        SkillThree:'MySQL'
    },
    regeditTime:new Date()
}
var workmate3={
    name:'cxw',
    age:20,
    sex:1,
    job:'UI设计',
    skill:{
        skillOne:'PhotoShop',
        SkillTwo:'UI',
        SkillThree:'Word+Excel+PPT'
    },
    regeditTime:new Date()
}
var db=connect('user')
var workmateArray=[workmate1,workmate2,workmate3]
db.workmate.insert(workmateArray)
print('The data was inserted successfully.');

上面的代码,以文件的形式向数据库中插入了3条数据。

1 修改指定字段


这时候突然发现UI职位的性别出现了错误,本来人家是个美女,这里错写成了男,我们需要修改这条数据,如果有过关系型数据库的经验的同学,经常会这样写。

db.workmate.update({name:'cxw'},{sex:0})

这样写的问题是,我们的最后一条数据变成了只有sex:0,其它数据全部丢失了,这肯定不是我们想要的。

【正确的修改方法】
可以声明一个变量,然后把要改变数据的全部信息放入变量,最后执行修改操作。

var db=connect('user')
var workmate3={
    name:'cxw',
    age:20,
    sex:0,
    job:'UI设计',
    skill:{
        skillOne:'PhotoShop',
        SkillTwo:'UI',
        SkillThree:'Word+Excel+PPT'
    },
    regeditTime:new Date()
}
db.workmate.update({name:'cxw'},workmate3)
print('The data was updated successfully');

上面的修改方法每次修改都需要把之前的数据带上,很不优雅简洁。update提供了修改器,帮助我们做这些事情。

【$set修改器】
用来修改一个指定的键值(key),这时候我们要修改上节课的sex和age就非常方便了,只要一句话就可以搞定。

同时修改多个字段
db.workmate.update({"name":"cxw"},{"$set":{sex:0,age:22}})

修改好后,我们可以用db.workmate.find()来进行查看,你会发现数据已经被修改。

2 修改嵌套内容(内嵌文档)


比如现在的UI的技能发生了变化,说她不会作PPT而是word作的很好,需要进行修改。这时候你会发现skill数据是内嵌的,这时候我们可以属性的形式进行修改,skill.skillThree,具体看下面的代码。

db.workmate.update({"name":"cxw"},{"$set":{"skill.SkillThree":'word'}})

3 删除文档中指定字段

【$unset用于将key删除】
它的作用其实就是删除一个key值和键。一般女孩子都是不希望看到自己的年龄的,所以要求我们把年龄删除。

db.workmate.update({"name":"cxw"},{$unset:{"age":''}})
db.getCollection('workmate').update({"name":"cxw"},{$unset:{"age":1}},true,false)

如果存在age,则删除字段age
db.workmate.update({"name":"cxw"}, {$unset: {'age': {$exists: true}}})

4 对指定数值型字段进行计算

【$inc  $mul对数字进行计算】
这是对value值的修改,但是修改的必须是数字,字符串是不起效果的。我们现在要对zl的年龄减去2岁,就可以直接用$inc来操作。

db.workmate.update({"name":"zl"},{$inc:{"age":-2}})

db.getCollection('workmate').update({"name":"zl"},{$mul:{"age":0.5}})

【$max 对数字型字段 进行设置】

设置highScore值,如果 字段值<870 ,则修改为870,取字段值和870 中较大的一个。

db.scores.update( { _id: 1 }, { $max: { highScore: 870 } } )  

5 每次更新多条数据

【multi选项】
现在领导说了,你要把每个人的爱好也加入进来,但是如果你直接写会只加一个,比如下面这种形式。

db.workmate.update({},{$set:{interset:[]}})

这时候你用db.workmate.find()查找,你会发现只改变了第一个数据,其他两条没有改变。这时候我们想改变就要用到multi选项。

db.workmate.update({},{$set:{interset:[]}},{multi:true})

这时候每个数据都发生了改变,multi是有ture和false两个值,true代表全部修改,false代表只修改一个(默认值)。

6 如果需要更新的数据不存在就插入,存在就更新,怎吗实现?

【upsert选项】
upsert是在找不到值的情况下,直接插入这条数据。比如我们这时候又来了一个新同事xw,我们这时候修改他的信息,age设置成20岁,但集合中并没有这条数据。这时候可以使用upsert选项直接添加。

db.workmate.update({name:'xw'},{$set:{age:20}},{upsert:true})

upsert也有两个值:true代表没有就添加,false代表没有不添加(默认值)。

上面是一些基础的修改器,接下来主要是数组修改器的操作,当然也可以修改内嵌文档,也就是对象形式的数据。

7 对数组字段添加数据 
 

【$push追加数组】
$push的功能是追加数组中的值,但我们也经常用它操作内嵌文档,就是{}对象型的值。先看一个追加数组值的方式,比如我们要给小王加上一个爱好(interset)为画画(draw):

db.workmate.update({name:'cxw'},{$push:{interest:'draw'}})

当然$push修饰符还可以为内嵌文档数组字段增加值

db.workmate.update({name:'cxw'},{$push:{"skill.skillFour":'draw'}})

返回结果为 

{  
    "skill" : {
        "skillOne" : "PhotoShop",
        "SkillTwo" : "UI",
        "SkillThree" : "Word+Excel+PPT",
        "skillFour" : [ 
            "draw"
        ]
    }
}

如果我们想要为skill 增加第五项技能,可以是用$set

db.workmate.update({name:'cxw'},{$set:{"skill.skillFive":'draw'}})
"skill" : {
        "skillOne" : "PhotoShop",
        "SkillTwo" : "UI",
        "SkillThree" : "Word+Excel+PPT",
        "skillFour" : [ 
            "draw"
        ],
        "skillFive" : "draw"
    }

8 向数组添加数据前,先判断数据是否存在

【$ne查找是否存在】
它的作用是,检查一个值是否存在。
如果xiaoWang的爱好(interest)里没有palyGame这个值,我们就加入Game这个爱好。

db.workmate.update({name:'xw',"interest":{$ne:'playGame'}},{$push:{interest:'Game'}})

查询interest数组里不包含这个值的文档,并把game 添加进去。

mongo 还提供了另外一个操作符,包含了$ne 和 $push 的合并效果

【$addToSet 升级版的$ne】
它是$ne的升级版本(查找是否存在,不存在就push上去),操作起来更直观和方便,所以再工作中这个要比$en用的多。
我们现在要查看小王(xiaoWang)兴趣(interest)中有没有阅读(readBook)这项,没有则加入读书(readBook)的兴趣.

db.workmate.update({name:"xiaoWang"},{$addToSet:{interest:"readBook"}})

9.1 向数组中 添加多个值

【$each 批量追加】
它可以传入一个数组,一次增加多个值进去,相当于批量操作,性能同样比循环操作要好很多,这个是需要我们注意的,工作中也要先组合成数组,然后用批量的形式进行操作。
我们现在要给xw,一次加入三个爱好,唱歌(Sing),跳舞(Dance),编码(Code)。

var newInterset=["Sing","Dance","Code"];
db.workmate.update({name:"xw"},{$addToSet:{interest:{$each:newInterset}}})

此处不能直接写成

var newInterset=["Sing","Dance","Code"];
db.workmate.update({name:"xw"},{$addToSet:{interest:newInterset}})

这样的效果是 interest 里多了一个数组对象,而不是多了3个值。

9.2向数组特定位置添加多个值

想数组特定位置添加元素

db.students.update( {name: "xw" },{$push: {interest: {$each:newInterset,$position: 0 }}}}

$push 和$addToSet 的区别就是添加之前会不会判断是否已经存在

9.3向数组中添加数据的时候,如何保证入库顺序?  $Sort :指定排序字段

The $sort modifier orders the elements of an array during a $push operation.

To use the $sort modifier, it must appear with the $each modifier. You can pass an empty array [] to the $each modifier such that only the $sort modifier has an effect.

db.students.update( { name: "xxx" }, {$push: {quizzes: {$each: [ { id: 3, score: 8 }, { id: 4, score: 7 }, { id: 5, score: 6 } ],$sort: { score: 1 }}}}}

10 删除数组中的开头或者结尾的值 或者满足某个条件的值

【$pop 删除数组值】
$pop只删除一次,并不是删除所有数组中的值。而且它有两个选项,一个是1和-1。
1:从数组末端进行删除
-1:从数组开端进行删除
例子:现在要删除xiaoWang的编码爱好(code)。

db.workmate.update({name:'xw'},{$pop:{interest:1}})

移除interest数组中的draw元素

db.profiles.update( { name: "xw" }, { $pull: { interest: draw } } );

移除interest数组中的以draw开头的元素

db.profiles.update( { name: "xw" }, { $pull: { interest:{$regex:/^draw/i} } } );

11 修改数组中指定位置的值

【数组定位修改】
有时候只知道修改数组的第几位,但并不知道是什么,这时候我们可以使用interest.int 的形式。
例子,比如我们现在要修改xiaoWang的第三个兴趣为编码(Code),注意这里的计数是从0开始的。

db.workmate.update({name:'xw'},{$set:{"interest.2":"Code"}})

定位操作符("$")作为第一个匹配查询条件的元素的占位符,也就是在数组中的索引值。

db.students.insert({ "_id" : 1, "grades" : [ 78, 88, 88 ] });

//查询匹配的文档中,数组有2个88,只更新第一个匹配的元素,也就是"grades.1"

db.students.update( { _id: 1, grades: 88 }, { $set: { "grades.$" : 82 } }) ;

db.students.insert({ "_id" : 2, "grades" : [ 88, 90, 92 ] });

//查询文档中没有出现grades字段,查询报错

db.students.update( { _id: 2 }, { $set: { "grades.$" : 82 } } );

12 重命名字段

重命名字段(把當前字段名刪除,把value赋值给新的key)

如果文档中存在A、B字段,将B字段重命名为A,$rename会将A字段和值移除掉,然后将B字段名改为A.

$rename操作符也可以将子文档中键值移到其他子文档中

db.students.update( { _id: 1 }, { $rename: { 'nickname': 'alias', 'cell': 'mobile' } } )

13 如果想要新增字段,使其等于另外一个字段的值,可以

db.getCollection('ss').find({"mobile":{$exists:true}}).forEach(function(item){

    item.a=item.b

    db.getCollection('xx').save(item)

});

14 同时使用多个操作符

把字段a的值修改为c ,同时向interest 添加多条数据,如果不存在就增加。

db.workmate.update({"name": "xx"}, {"$set": {"a": "c"}, "$addToSet": {"interest": {"$each" :["a", "c"]}}}, true)

15 设置某个字段为 当前日期 ,类型为 iosdate 或者timestamp

db.workmate.update({name:'cxw'},{$currentDate:{"a":{$type:"date"}}})

db.workmate.update({name:'cxw'},{$currentDate:{"b":true}})

db.workmate.update({name:'cxw'},{$currentDate:{"c":{$type:"timestamp"}}})

16 删除并且返回文档指定字段

var old_item = db.xx.findAndModify({query: {"_id": "s"}, fields:{"D": 1,'E':1, 'F':1}, remove: true})

17 文档替换

要更新除 _id 字段外文档的整个内容,传递一个全新的文档给 db.collection.replaceOne() 或者 db.collection.update() 作为第二个参数。当替换文档时,替换的文档必须仅仅由 <field> : <value> 组成.

替换文档可以有不同于原文档的字段。在替换文档中,由于 _id 字段是不变的,所以,你可以省略 _id 字段;不论如何,如果你包含了 _id 字段,它的值必须和当前的值相同。

db.users.replaceOne( { name: "abc" }, { name: "amy", age: 34, type: 2, status: "P", favorites: { "artist": "Dali", food: "donuts" } } )

db.users.update( { name: "abc" }, { name: "amy", age: 34, type: 2, status: "P", favorites: { "artist": "Dali", food: "donuts" } } )

删除delete

删除操作从集合中删除文档:

db.workmate.deleteOne( filter, <optional params> ) - delete first matching document, optional parameters are: w, wtimeout, j
db.workmate.deleteMany( filter, <optional params> ) - delete all matching documents, optional parameters are: w, wtimeout, 

db.workmate.findOneAndDelete( filter, <optional params> ) // 原子性

db.workmate.remove(query)

在MongoDB中,删除操作以单个集合为目标。MongoDB中的所有写操作都是单文档级别的原子操作。

批量操作 bulkwrite

db.workmate.bulkWrite( operations, <optional params> ) - bulk execute write operations, optional parameters are: w, wtimeout, j
 

写操作

insertOne

插入单个文档到集合中。

1

2

3

db.collection.bulkWrite( [

   { insertOne : { "document" : <document> } }

] )

updateOne 及 updateMany

updateOne 更新集合中 filter 匹配的单个文档。如果匹配到多个文档 updateOne 仅更新第一个匹配到的文档。

1

2

3

4

5

6

7

8

9

db.collection.bulkWrite( [

   { updateOne :

      {

         "filter" : <document>,

         "update" : <document>,

         "upsert" : <boolean>

      }

   }

] )

updateMany 更新集合中所有匹配到的文档。

1

2

3

4

5

6

7

8

9

db.collection.bulkWrite( [

   { updateMany :

      {

         "filter" : <document>,

         "update" : <document>,

         "upsert" : <boolean>

      }

   }

] )

对字段的更新操作例如 $set 、$unset 、$rename等。

默认情况 upsert 为 false。

replaceOne

replaceOne 替换集合中 filter 匹配到的单个文档。如果匹配到多个文档 replaceOne 只会替换一个匹配到的文档。

1

2

3

4

5

6

7

8

9

db.collection.bulkWrite([

   { replaceOne :

      {

         "filter" : <document>,

         "replacement" : <document>,

         "upsert" : <boolean>

      }

   }

] )

replacement 字段中不能包含 update 操作。

默认情况 upsert 为 false。

deleteOne 及 deleteMany

deleteOne 删除集合中 filter 匹配到的单个文档。如果匹配到多个文档 deleteOne 只会删除一个匹配到的文档。

1

2

3

db.collection.bulkWrite([

   { deleteOne :  { "filter" : <document> } }

] )

deleteMany 删除集合中 filter 匹配到的所有文档。

1

2

3

db.collection.bulkWrite([

   { deleteMany :  { "filter" : <document> } }

] )

_id 字段

如果文档未指定 _id 字段,则mongod会在 insert 或 upsert 文档之前添加 _id 字段并指定唯一的ObjectId。 大多数驱动程序会创建一个ObjectId并插入到 _id 字段,但如果驱动程序或应用程序没有,mongod将创建并填充 _id。

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

更新或替换操作不能指定与原始文档不同的 _id 值。

执行操作

ordered 参数指定  bulkWrite() 是否有序执行,默认情况下是有序执行。

含有6个操作的 bulkWrite()  代码如下:

1

2

3

4

5

6

7

8

9

10

db.collection.bulkWrite(

   [

      { insertOne : <document> },

      { updateOne : <document> },

      { updateMany : <document> },

      { replaceOne : <document> },

      { deleteOne : <document> },

      { deleteMany : <document> }

   ]

)

默认情况下 ordered : true ,每个操作将会有序的执行,从第一个insertOne 到最后一个deleteMany 顺序执行。

应用程序不依赖操作执行顺序是,可以设置 ordered 为 false ,此时mongod 会重新排序操作来提高性能。

含有6个操作无序的 bulkWrite()  代码如下:

1

2

3

4

5

6

7

8

9

10

11

db.collection.bulkWrite(

   [

      { insertOne : <document> },

      { updateOne : <document> },

      { updateMany : <document> },

      { replaceOne : <document> },

      { deleteOne : <document> },

      { deleteMany : <document> }

   ],

   { ordered : false }

)

对于ordered:false,操作结果可能会有所不同。 例如,deleteOne或deleteMany 删除的文档可能会变多或变少,具体取决于deleteOne或deleteMany 是在insertOne,updateOne,updateMany或replaceOne操作之前或之后的运行。

每组操作最多可以有1000次操作。 如果一个组超过此限制,MongoDB会将该组划分为1000或更小的组。 例如,如果队列包含2000个操作,MongoDB将创建2个组,每个组具有1000个操作。

大小和分组机制是内部的执行细节,在将来的版本中可能会有所变化。

在分片集合上执行有序操作通常比执行无序操作慢,因为对于有序,每个操作必须等待上一个操作完成。

固定集合(Capped Collections)

bulkWrite() 写操作在固定集合上使用有所限制。

  • updateOne 和 updateMany 更新时增加了被修改文档的大小将会抛出 WriteError

  • replaceOne 操作替换的文档比之前的文档大会抛出 WriteError

  • deleteOne 和 deleteMany 操作在固定集合上会抛出 WriteError

操作处理(Error Handling)

bulkWrite() 在错误发生时会抛出 BulkWriteError 异常。

排除Write Concern错误,有序操作在发生错误后停止,及无序操作继续处理队列中的剩余写入操作。

Write Concern 错误显示在 writeConcernErrors字段中,而所有其他错误都显示在writeErrors字段中。 如果遇到错误,则显示成功写入操作的数量而不是插入的_id值。 有序操作显示遇到的单个错误,而无序操作显示数组中的每个错误。

实例

批量写

characters 集合包含以下文档:

1

2

3

"_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() 在集合上执行批量操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

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);

}

操作结果如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

{

   "acknowledged" true,

   "deletedCount" : 1,

   "insertedCount" : 2,

   "matchedCount" : 2,

   "upsertedCount" : 0,

   "insertedIds" : {

      "0" : 4,

      "1" : 5

   },

   "upsertedIds" : {

   }

}

如果 第二个 insertOne 操作的 _id 是集合中已经存在的,则会抛出以下错误:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

BulkWriteError({

   "writeErrors" : [

      {

         "index" : 0,

         "code" : 11000,

         "errmsg" "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }",

         "op" : {

            "_id" : 5,

            "char" "Taeln"

         }

      }

   ],

   "writeConcernErrors" : [ ],

   "nInserted" : 1,

   "nUpserted" : 0,

   "nMatched" : 0,

   "nModified" : 0,

   "nRemoved" : 0,

   "upserted" : [ ]

})

默认情况下 ordered 为 true, 顺序执行时遇到错误就停止执行(后续的操作不会被执行)。

无序批量写

characters 集合包含以下文档:

1

2

3

"_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() 在集合上执行批量操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

try {

   db.characters.bulkWrite(

         [

            { insertOne :

               {

                  "document" :

                  {

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

                  }

               }

            },

            { insertOne :

               {

                  "document" :

                     {

                        "_id" : 4, "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 }

               }

            }

         ],

            { ordered : false }

      );

   }

   catch (e) {

   print(e);

}

操作结果如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

BulkWriteError({

   "writeErrors" : [

      {

         "index" : 0,

         "code" : 11000,

         "errmsg" "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4 }",

         "op" : {

            "_id" : 4,

            "char" "Taeln"

         }

      }

   ],

   "writeConcernErrors" : [ ],

   "nInserted" : 1,

   "nUpserted" : 0,

   "nMatched" : 2,

   "nModified" : 2,

   "nRemoved" : 1,

   "upserted" : [ ]

})

无序操作,尽管操作过程中出现错误,剩余的操作也不会就此终止执行。

基于 Write Concern 的批量写

enemies 集合包含以下文档:

1

2

3

4

"_id" : 1, "char" "goblin""rating" : 1, "encounter" : 0.24 },

"_id" : 2, "char" "hobgoblin""rating" : 1.5, "encounter" : 0.30 },

"_id" : 3, "char" "ogre""rating" : 3, "encounter" : 0.2 },

"_id" : 4, "char" "ogre berserker" "rating" : 3.5, "encounter" : 0.12}

以下使用 write concern 值为 "majority" 及 timeout 为 100 毫秒来执行批量写操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

try {

   db.enemies.bulkWrite(

      [

         { updateMany :

            {

               "filter" : { "rating" : { $gte : 3} },

               "update" : { $inc : { "encounter" : 0.1 } }

            },

         },

         { updateMany :

            {

               "filter" : { "rating" : { $lt : 2} },

               "update" : { $inc : { "encounter" : -0.25 } }

            },

         },

         { deleteMany : { "filter" : { "encounter" { $lt : 0 } } } },

         { insertOne :

            {

               "document" :

                  {

                     "_id" :5, "char" "ogrekin" "rating" : 2, "encounter" : 0.31

                  }

            }

         }

      ],

      { writeConcern : { w : "majority", wtimeout : 100 } }

   );

}

catch (e) {

   print(e);

}

如果副本集中所有必需节点确认写入操作所需的总时间大于wtimeout,则在wtimeout 时间过去时将显示以下writeConcernError。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

BulkWriteError({

   "writeErrors" : [ ],

   "writeConcernErrors" : [

      {

         "code" : 64,

         "errInfo" : {

            "wtimeout" true

         },

         "errmsg" "waiting for replication timed out"

      }

   ],

   "nInserted" : 1,

   "nUpserted" : 0,

   "nMatched" : 4,

   "nModified" : 4,

   "nRemoved" : 1,

   "upserted" : [ ]

   })

结果集显示执行的操作,因为writeConcernErrors错误不是任何写入操作失败的标志。

MongoDB操作符

Query and Projection Operators

1.比较运算符

名称描述
$eq等于 =
$gt大于 >
$gte大于等于 >=
$in匹配数组中指定的任何值,类似于mysql的IN操作
$lt小于 <
$lte小于等于 <=
$ne不等于
$nin类似于mysql的NOT IN操作

2.逻辑运运算符

名称描述
$and逻辑与
$not反转查询表达式。返回与查询表达式不匹配的文档
$nor使用逻辑NOR连接查询子句。返回无法匹配两个子句的所有文档
$or使用逻辑OR连接查询子句。返回与任一子句的条件匹配的所有文档

3.元素操作符

名称描述
$exists匹配具有指定字段的文档
$type如果字段是指定类型,则选择文档

4 Evaluation

NameDescription
$expr

Allows use of aggregation expressions within the query language.

比较同一个文档中的两个字段 可以配合$cond使用

$jsonSchema

Validate documents against the given JSON Schema.

查询满足特定json格式的文档

$mod

Performs a modulo operation on the value of a field and selects documents with a specified result.

查询字段 对m 取余等于n 的文档

$regex

Selects documents where values match a specified regular expression.

查询字段匹配正则表达式的文档

$text

Performs text search.

查询文本字段包含特定字符串的文档

$where

Matches documents that satisfy a JavaScript expression.

查询满足某个条件的文档 ,用于指定一个函数

 5 Geospatial

NameDescription
$geoIntersects

Selects geometries that intersect with a GeoJSON geometry. The 2dsphere index supports $geoIntersects.

查询球面索引字段  和 指定的区域有交集的文档

$geoWithin

Selects geometries within a bounding GeoJSON geometry. The 2dsphere and 2d indexes support $geoWithin.

查询 字段  在指定区域范围内的文档

$near

Returns geospatial objects in proximity to a point. Requires a geospatial index. The 2dsphere and 2d indexes support $near.

查询 字段 在某个点附近的文档 ,由近及远 (平面距离)

$nearSphere

Returns geospatial objects in proximity to a point on a sphere. Requires a geospatial index. The 2dsphere and 2d indexes support $nearSphere.

查询 字段 在某个点附近的文档 ,由近及远 (球面距离)

6 Array

NameDescription
$allMatches arrays that contain all elements specified in the query.
$elemMatchSelects documents if element in the array field matches all the specified $elemMatch conditions.
$sizeSelects documents if the array field is a specified size.

7 Bitwise

NameDescription
$bitsAllClear

Matches numeric or binary values in which a set of bit positions all have a value of 0.

获取字段的一组位置都是0值的文档

$bitsAllSet

Matches numeric or binary values in which a set of bit positions all have a value of 1.

获取字段的一组位置都是1值的文档

$bitsAnyClearMatches numeric or binary values in which any bit from a set of bit positions has a value of 0.
$bitsAnySetMatches numeric or binary values in which any bit from a set of bit positions has a value of 1.

8 Projection Operators

NameDescription
$Projects the first element in an array that matches the query condition.
$elemMatchProjects the first element in an array that matches the specified $elemMatch condition.
$metaProjects the document’s score assigned during $text operation.
$sliceLimits the number of elements projected from an array. Supports skip and limit slices.

Update Operators

1 field

NameDescription
$currentDateSets the value of a field to current date, either as a Date or a Timestamp.
$incIncrements the value of the field by the specified amount.
$minOnly updates the field if the specified value is less than the existing field value.
$maxOnly updates the field if the specified value is greater than the existing field value.
$mulMultiplies the value of the field by the specified amount.
$renameRenames a field.
$setSets the value of a field in a document.
$setOnInsertSets the value of a field if an update results in an insert of a document. Has no effect on update operations that modify existing documents.
$unsetRemoves the specified field from a document.

Array

Operators

NameDescription
$

Acts as a placeholder to update the first element that matches the query condition.

作为一个替代符号 用来更新第一个匹配查询条件的数组元素

db.students.updateOne(
   { _id: 1, grades: 80 },
   { $set: { "grades.$" : 82 } }
)
$[]

Acts as a placeholder to update all elements in an array for the documents that match the query condition.

作为一个替代符号,用来指代数组中的每一个元素。

db.collection.update(
   { myArray: [ 5, 8 ] },
   { $set: { "myArray.$[]": 10 } },
   { upsert: true }
)
$[<identifier>]

Acts as a placeholder to update all elements that match the arrayFilters condition for the documents that match the query condition.

作为一个标识符 用来表示 匹配arrayFilters 指定的数组里代表的元素

db.collection.update(
   { myArray: [ 0, 1 ] },
   { $set: { "myArray.$[element]": 2 } },
   { arrayFilters: [ { element: 0 } ],
     upsert: true }
)
$addToSetAdds elements to an array only if they do not already exist in the set.
$popRemoves the first or last item of an array.
$pull

Removes all array elements that match a specified query.

删除所有匹配特定查询的数组元素

db.stores.update(
    { },
    { $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } },
    { multi: true }
)
$pushAdds an item to an array.
$pullAll

Removes all matching values from an array.
db.survey.update( { _id: 1 }, { $pullAll: { scores: [ 0, 5 ] } } )

删除文档中数组内对应的元素(用数组方式定义的[0,5]  )

Modifiers

NameDescription
$eachModifies the $push and $addToSet operators to append multiple items for array updates.
$positionModifies the $push operator to specify the position in the array to add elements.
$sliceModifies the $push operator to limit the size of updated arrays.
$sortModifies the $push operator to reorder documents stored in an array.

Bitwise

NameDescription
$bitPerforms bitwise ANDOR, and XOR updates of integer values.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值