目 录CONTENT

文章目录

MongoDB 学习

小张的探险日记
2021-09-07 / 0 评论 / 0 点赞 / 507 阅读 / 22,648 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-12-16,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1.MongoDB 简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

mongodb 是一种 NoSql 的数据库,与Mysql 这种关系型数据库不一样,它是一种非关系型数据库。

NoSql 常用于大规模的数据储存,例如 用户信息搜集,用户登陆信息,访问信息等,这些数据没有固定的结构,这些NoSql 都能很好的支持,无需多余操作就能方便的横向扩展。

mongodb 的储存结构是 二进制的 json。

img

NoSql 的优缺点:

​ 优点:

  • - 高可扩展性
  • - 分布式计算
  • - 低成本
  • - 架构的灵活性,半结构化数据
  • - 没有复杂的关系

缺点:

  • - 没有标准化
  • - 有限的查询功能(到目前为止)
  • - 最终一致是不直观的程序

2.NoSQL 数据库分类

类型部分代表特点
列存储HbaseCassandraHypertable顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。
文档存储MongoDBCouchDB文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。
key-value存储Tokyo Cabinet / TyrantBerkeley DBMemcacheDBRedis可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)
图存储Neo4JFlockDB图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。
对象存储db4oVersant通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。
xml数据库Berkeley DB XMLBaseX高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。

3.MongoDB 与 Mysql 对比

MysqlMongoDB解释
DataBaseDataBase数据库
tablecollection表/集合
rowdocument/BSON数据行/文档
columnfield列/域
indexindex索引
table joins$lookup多表关联,3.2 版本新增🤩
primary keyprimary id主键,mongo 的 _id 为默认主键

4 MongDb 操作语法

4.1 创建集合

//创建集合
db.createCollection("test1")
//插入文档同时创建文档
db.test2.insert({"name":"test1"})

db.createCollection("mycol", {
    capped: true,
    autoIndexId: true,
    size: 
    6142800,//指定字节数,超过后覆盖
    max: 10000 //指定最大文档数,超过后覆盖
})

4.2 删除集合

//test1 为 集合名称
db.test1.drop()

4.3 插入文档

​ 文档的数据结构跟json 数据结构一致,文档在mongodb 中存储的结构为BJSON。

BJSON 是一种二进制的JSON,Binary Json 简称 BJSON。

语法如下:

​ db.COLLECTION_NAME.save( document ) // 最新版本已废除

​ 主键重复则报错,options 支持指定写入策略( writeConcern 默认 1,要求确认写操作)及写入顺序( ordered 默认true)。

​ db.COLLECTION_NAME.insert( document,options )

db.test2.insert({"_id":"2","name":"那么多2"})

db.test2.insertOne({"_id":"3","name":"那么多2"})

db.test2.insertMany([
{"name":"111111b","age":100},
{"name":"222222b","age":199},
{"name":"333333b","age":100},
{"name":"444444b","age":199},
{"name":"555555b","age":100},
{"name":"666666b","age":199}
])

4.4 更新文档

​ update 方法用于已更存在的文档。语法格式如下:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。

使用案例:

​ //搜索 name=111111b 的 修改 name 为 ak47,默认只会修改符合条件的第一条数据,如需修改多条 则需要设置 multi 参数为 true。

db.test2.update({"name":"111111b"},{$set:{"name":"ak47"}})
// multi 使用案例
db.test2.update({"name":"test1"},{$set:{"name":"ak47"}},{multi:true})
只更新第一条记录:

db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );
全部更新:

db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );
只添加第一条:

db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
全部添加进去:

db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );
全部更新:

db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );
只更新第一条记录:

db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

4.5 删除文档

​ 语法格式:

db.collection.remove(<query>,{justOne:<boolean>,writeConcern:<document>})

​ 使用案例

​ 删除 name = ak47 的,只删除一个,justOne 默认为 false 则删除所有。

db.test2.remove({name : "ak47"},{justOne:true})

4.6 查询文档

​ 语法格式:

db.collection.find(query, projection)
//只返回一个文档
db.collection.findOne(query, projection)
  • query :可选,使用查询操作符指定查询条件
  • projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。

使用案例:

//查询 name = test1 的,且只查询 name(此处为 projection)
db.test2.find({name:"test1"},{name:1})
// AND 条件用法
db.test2.find({name:"sssssssd",age:100})
// OR 条件用法,此处 $or 使用了 查询选择器
db.test2.find({$or:[{name:"sssssssd"},{age:199}]})
// OR 和 AND 条件连用,此处 $or 使用了 查询选择器
db.test2.find({name:"666666a",$or:[{name:"sssssssd"},{age:199}]})

4.7 查询选择器和投影运算符

比较选择器

名字 描述
$eq 判断相等
$gt 判断大于
$gte 判断大于等于
$in 判断在其中
$lt 判断小于
$lte 判断小于等于
$ne 判断所有值都不等于指定值
$nin 判断不在其中

db.student.insertMany([
{name:"a1",age:18,sex:0},
{name:"b1",age:23,sex:1},
{name:"c1",age:44,sex:0},
{name:"d1",age:66,sex:0},
{name:"e1",age:777,sex:1},
{name:"f1",age:11,sex:0},
{name:"g1",age:28,sex:0},
{name:"h1",age:38,sex:3},
{name:"i1",age:48,sex:0},
{name:"j1",age:58,sex:0},
{name:"k1",age:64,sex:2},
{name:"l1",age:121,sex:0},
{name:"m1",age:234,sex:1},
{name:"n1",age:346,sex:0},
{name:"o1",age:65,sex:0},
{name:"p1",age:34,sex:0},
{name:"q1",age:656,sex:3},
{name:"r1",age:678,sex:0},
{name:"s1",age:23,sex:0}

])


//查询所有
db.student.find()
//等于查询
db.student.find({name:"a1"})
db.student.find({name:{$eq:"a1"}})
//age 小于 18
db.student.find({age:{$lt:18}})
//age 小于等于 18
db.student.find({age:{$lte:18}})
//age 大于 23
db.student.find({age:{$gt:23}})
//age 大于等于 23
db.student.find({age:{$gte:23}})
//name 不等于 db
db.student.find({name:{$ne:"b1"}})
// age 在 18/23/44
db.student.find({age:{$in:[18,23,44]}})
// age 不在 18/23/44范围内 的其他数据
db.student.find({age:{$nin:[18,23,44]}})

逻辑选择器

$and 与
$not 非
$nor 异或
$or 或

// $and 并且条件查询
db.student.find({
    $and: [
		{
        name: "a1"
    },{
        age: 18
    }]
})
// $or 或者条件查询
db.student.find({
	$or:[{name:"a1"},{age:23}]
})
//查询 age 不在大于 23 的范围内的数据
db.student.find({age:{$not:{$gt:23}}})
// 条件取反查询,如: age 不等于 23 的
db.student.find({$nor:[{age:23}]})
元素选择器

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

//查询 name 字段 数据类型是 string的
db.student.find({"name":{$type:'string'}})
//匹配字段是否含有 name 字段,true 表示匹配含有的,false 表示匹配没有的
db.student.find({name:{$exists:true}})
评估选择器

$expr 允许在查询语言中使用聚合表达式。

//$expr 表达式,匹配 sex 字段的值 和 age 字段值相等的
db.student.find({$expr:{$eq:["$sex","$age"]}})
//需求:qty 数量大于100 的任何商品 可以获得 50% 的折扣,否则打 25% 折扣
//准备测试数据
db.supplies.insertMany([
{ "_id" : 1, "item" : "binder", "qty" : 100 , "price" : 12 },
{ "_id" : 2, "item" : "notebook", "qty" : 200 , "price" : 8 },
{ "_id" : 3, "item" : "pencil", "qty" : 50 , "price" : 6 },
{ "_id" : 4, "item" : "eraser", "qty" : 150 , "price" : 3 },
{ "_id" : 5, "item" : "legal pad", "qty" : 42 , "price" : 10}
])

db.supplies.find()

db.supplies.find({
	$expr:{
		$lt:[{
			$cond:{
				if:{$gte:["$qty",100]},
				then:{$multiply:["$price",0.50]},
				else:{$multiply:["$price",0.75]}
			}
		},5]}
})

$jsonSchema 根据给定的JSON模式验证文档。

//定义以下示例架构对象:

let myschema =  {
      required: [ "item", "qty", "instock" ],
      properties: {
         item: { bsonType: "string" },
         qty: { bsonType: "int" },
         size: {
            bsonType: "object",
            required: [ "uom" ],
            properties: {
               uom: { bsonType: "string" },
               h: { bsonType: "double" },
               w: { bsonType: "double" }
            }
          },
          instock: { bsonType: "bool" }
      }
 }
//您可以使用$jsonSchema查找集合中满足模式的所有文档:
db.inventory.find( { $jsonSchema: myschema } )
db.inventory.aggregate( [ { $match: { $jsonSchema: myschema } } ] )

$mod 对字段值执行模运算,并选择具有指定结果的文档。

// 取模,age 除以4=0 的数据
db.student.find({age:{$mod:[4,0]}})

$regex 选择值与指定正则表达式匹配的文档。

//示例将集合products与以下文档一起使用:
db.productes.insertMany(
[
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." },
{ "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" },
{ "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before     line" },
{ "_id" : 103, "sku" : "xyz789", "description" : "aaaaaaa"}
]
)
//匹配sku 字段类似 "%789" 的文档
db.productes.find( { sku: { $regex: /789$/ } } )

$text 执行文本搜索。

$text运算符接受具有以下字段的文本查询文档:

FieldTypeDescription
$searchstringMongoDB 解析并用于查询文本索引的术语字符串。除非指定为短语,否则 MongoDB 会对术语进行逻辑OR搜索。有关该字段的更多信息,请参见Behavior
$languagestring可选的。确定用于搜索的停用词列表以及词干分析器和分词器规则的语言。如果未指定,则搜索使用索引的默认语言。有关支持的语言,请参见Literals 搜寻语言

限制🚫

  • 一个查询最多可以指定一个$text表达式。
  • $text查询不能出现在$nor表达式中。
  • $text查询不能出现在$elemMatch查询表达式或$elemMatch投影表达式中。
  • 要在$or表达式中使用$text查询,必须对$or数组中的所有子句构建索引。
  • 如果查询包含$text查询表达式,则不能使用hint()
  • 如果查询包含$text表达式,则不能指定$natural排序 Sequences。
  • 您不能将需要特殊text index$text表达式与需要不同类型的特殊索引的查询运算符组合在一起。例如,您不能将$text表达式与$near运算符组合。
  • Views不支持文本搜索。

如果在聚合中使用$text运算符,则以下限制也适用。

  • 包含$text$match阶段必须是管道中的“第一”阶段。
  • text运算符在该阶段只能出现一次。
  • text运算符表达式不能出现在$or$not表达式中。
  • 默认情况下,文本搜索不会按匹配分数的 Sequences 返回匹配的文档。在$sort阶段使用$meta聚合表达式。
// $text 支持 对text index 索引的字段的内容执行文本搜索
//语法格式如下:
{
  $text:
    {
      $search: <string>,
      $language: <string>,
      $caseSensitive: <boolean>, //是否区分大小写,默认false,不区分
      $diacriticSensitive: <boolean>//是否区分 变音符号,默认false,不敏感
    }
}


//准备测试数据
db.articles.insert(
   [
     { _id: 1, subject: "coffee", author: "xyz", views: 50 },
     { _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
     { _id: 3, subject: "Baking a cake", author: "abc", views: 90  },
     { _id: 4, subject: "baking", author: "xyz", views: 100 },
     { _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
     { _id: 6, subject: "Сырники", author: "jkl", views: 80 },
     { _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
     { _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
   ]
)
//创建索引
db.articles.createIndex( { subject: "text" } )

//模糊搜索单个单词
db.articles.find( { $text: { $search: "coffee" } } )
//结果
1	coffee	xyz	50
7	coffee and cream	efg	10
2	Coffee Shopping	efg	5
//or 方式匹配 多个单词
db.articles.find( { $text : { $search : "con leche"} })
//结果
8	Cafe con Leche	xyz	10
5	Café Con Leche	abc	200

//搜索短语
db.articles.find({$text : {$search : "\"and cream\""}})
//结果
7	coffee and cream	efg	10

//排除单词搜索,含有 coffee 不含shop
db.articles.find({$text : {$search : "coffee -shop"}})
//结果
1	coffee	xyz	50
7	coffee and cream	efg	10

//搜索其他语言
db.articles.find({$text : {$search : "leche",$language:"es"}})
//结果
8	Cafe con Leche	xyz	10
5	Café Con Leche	abc	200

//大小写区分/变音符号敏感
//默认 不区分大小写,不敏感变音符号
db.articles.find( { $text: { $search: "сы́рники CAFÉS" } } )
//结果
8	Cafe con Leche	xyz	10
5	Café Con Leche	abc	200
6	Сырники	jkl	80

//区分大小写搜索
db.articles.find( { $text: { $search: "Coffee", $caseSensitive: true } } )
//结果
2	Coffee Shopping	efg	5

//区分大小写的 短语
db.articles.find( {$text : {$search : "\"Café Con Leche\"", $caseSensitive: true}})
//结果
5	Café Con Leche	abc	200

//变音符号搜索
db.articles.find( { $text: { $search: "CAFÉ", $diacriticSensitive: true } } )
//结果
5	Café Con Leche	abc	200

//文档匹配分数
db.articles.find({$text : {$search:"coffee"}},{score:{$meta:"textScore"}})
//结果
1	coffee	xyz	50	1
2	Coffee Shopping	efg	5	0.75
7	coffee and cream	efg	10	0.75

//按匹配得分排序
db.articles.find({$text:{$search:"coffee"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}})
//结果
1	coffee	xyz	50	1
2	Coffee Shopping	efg	5	0.75
7	coffee and cream	efg	10	0.75

//按匹配得分排序后,取前两条
db.articles.find({$text:{$search:"coffee"}},{score:{$meta:"textScore"}}).sort({score:{$meta:"textScore"}}).limit(2)

//条件查询 + $text 搜索的 排序结果
db.articles.find(
		{
    author: "xyz",
    $text: {
        $search: "coffee con"
    }},
    {score: {
        $meta: "textScore"
    }}
).sort({
    date: 1,
    score: {
        $meta: "textScore"
    }
})
//结果
1	coffee	xyz	50	1
8	Cafe con Leche	xyz	10	0.666666666666667

$where 匹配满足JavaScript表达式的文档。

🥶应该尽量避免使用 $where ,会对速度有很大影响,因为$where 需要把BSON 数据转化为Javascript对象,然后再通过where 条件判断,同时不能使用索引。

db.students.insertMany([{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] },{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] },{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] },{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] },{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] },{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }])//JavaScript 字符串形式db.students.find({$where:"this._id == this.semester"})//JavaScript 函数形式db.students.find({$where:function(){return this._id == this.semester;}})//JavaScript 函数形式 查询 文档中 字段相等的文档db.students.find({$where:function(){	for(var item in this){		for(var otherItem in this){			if(item != otherItem && this[item] == this[otherItem]){				return true;			}		}	}	return false;}})
地理空间选择器

$geoIntersects 选择与几何图形相交的几何图形。二维球面索引支持$geoIntersects.
$geoWithin 选择边界几何图形中的几何图形。二维球面和二维索引支持$geoWithin.
$near 返回点附近的地理空间对象。需要地理空间索引。2dsphere和2d索引支持$near。
$nearSphere 返回球体上某个点附近的地理空间对象。需要地理空间索引。2dsphere和2d indexes支持$近岸球体。

参考 地理空间文档

数组选择器

$all 匹配包含查询中指定的所有元素的数组。

//测试数据db.students.insertMany([{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] },{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] },{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] },{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] },{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] },{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }])db.school.insertMany([{ _id: 1, zipcode: "63109", students: [              { name: "john", school: 102, age: 10 },              { name: "jess", school: 102, age: 11 },              { name: "jeff", school: 108, age: 15 }           ]},{ _id: 2, zipcode: "63110", students: [              { name: "ajax", school: 100, age: 7 },              { name: "achilles", school: 100, age: 8 },           ]},{ _id: 3, zipcode: "63109", students: [              { name: "ajax", school: 100, age: 7 },              { name: "achilles", school: 100, age: 8 },           ]},{ _id: 4, zipcode: "63109", students: [              { name: "barney", school: 102, age: 7 },              { name: "ruth", school: 102, age: 16 },           ]}])db.students.find()//匹配数组 元素值 grades 中含有 70 的db.students.find({grades:{$all:[70]}})db.school.find()//查询 students 数组中的对象 name 等于 johndb.school.find({"students.name":{$all:["john"]}})

$elemMatch 如果数组字段中的元素匹配所有指定的$elemMatch条件,则选择文档。

//测试数据来源于 上一个案例db.students.find()//grades 数组含有 大于 90 的值,则认为符合要求db.students.find({	grades : {$elemMatch:{$gt : 90}}})db.school.find()//查询 students的 age 大于 10 的文档db.school.find({    "students": {        $elemMatch: {            "age": {$gt:10}        }    }})

$size 如果数组字段是指定的大小,则选择文档。

//查询 grades 数组长度为 3 的 db.students.find({	grades:{$size:3}})//查询 students 数组长度为 3 的 db.school.find({	students:{$size:3}})
位操作选择器

$bitsAllClear 匹配数值或二进制值,其中一组位位置的值都为0。
$bitsAllSet 匹配数值或二进制值,其中一组位位置的值都为1。
$bitsAnyClear 匹配数值或二进制值,其中一组位位置中的任意一位的值为0。
$bitsAnySet 匹配数值或二进制值,其中一组位位置中的任意一位的值为1。

参考位运算文档

注释选择器

$comment 向查询谓词添加注释。

参考注释文档

4.8投影操作

$ 投影数组中与查询条件匹配的第一个元素。

数组字段限制🚫

在处理数组投影时,MongoDB 需要满足以下条件:

  • 投影文档中只能出现一个位置$运算符。
  • 只有一个数组字段(该字段受$投影运算符限制)应出现在query document中。查询文档中的其他数组字段可能导致未定义的行为。
  • query document仅应在要投影的数组字段上包含一个条件。多个条件可能在内部相互覆盖并导致不确定的行为。
db.students.insertMany([{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] },{ "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] },{ "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] },{ "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] },{ "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] },{ "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }])//查询 semester=1 and grades 大于等于85,然后只返回 符合的第一个元素db.students.find({    semester: 1,    grades: {        $gte: 85    }},{"grades.$":1})//测试数据db.testStudent.insertMany([    {        "_id": 7,        semester: 3,        "grades": [{            grade: 80,            mean: 75,            std: 8        }, {            grade: 85,            mean: 90,            std: 5        }, {            grade: 90,            mean: 85,            std: 3        }]    },    {        "_id": 8,        semester: 3,        "grades": [{            grade: 92,            mean: 88,            std: 8        }, {            grade: 78,            mean: 90,            std: 5        }, {            grade: 88,            mean: 85,            std: 3        }]    }])//对象投影查询//查询出 gredes 中 mean 属性值 大于 70 的第一个元素db.testStudent.find({    "grades.mean": {        $gt: 70    }}, {    "grades.$": 1})
$elemMatch 投影数组中与指定的$elemMatch条件匹配的第一个元素。
db.school.insertMany([{ _id: 1, zipcode: "63109", students: [              { name: "john", school: 102, age: 10 },              { name: "jess", school: 102, age: 11 },              { name: "jeff", school: 108, age: 15 }           ]},{ _id: 2, zipcode: "63110", students: [              { name: "ajax", school: 100, age: 7 },              { name: "achilles", school: 100, age: 8 },           ]},{ _id: 3, zipcode: "63109", students: [              { name: "ajax", school: 100, age: 7 },              { name: "achilles", school: 100, age: 8 },           ]},{ _id: 4, zipcode: "63109", students: [              { name: "barney", school: 102, age: 7 },              { name: "ruth", school: 102, age: 16 },           ]}])db.school.find()//查询 zipCode 等于 63109 的 并且 students 的对象属性 school=102 and age>10 的 第一个符合的数据 db.school.find({    zipcode: "63109"},{    students: {        $elemMatch: {            school: 102,            age: {                $gt: 10            }        }    }})//结果1	[    {        name: "jess",        school: 102,        age: 11    }]3	4	[    {        name: "ruth",        school: 102,        age: 16    }]
$meta 投射在$text操作期间分配的文档分数。

参考文档案例

$slice 限制从数组投影的元素数量。支持跳过和限制切片。

// 控制 数组 返回的数量db.students.find({    semester: 1}, {    grades: {        $slice: 1    }})// 控制 数组 返回的数量,后两个db.students.find({    semester: 1}, {    grades: {        $slice: -2    }})// 控制 数组 返回的数量,跳过第一个,getdb.students.find({    semester: 1}, {    grades: {        $slice: [1,2]    }})

4.9 多表联查- $lookup

测试数据:

订单集合

db.orders.insert([   { "_id" : 1, "goodsName" : "almonds", "price" : 12, "quantity" : 2 },   { "_id" : 2, "goodsName" : "pecans", "price" : 20, "quantity" : 1 },   { "_id" : 3  }])

商品库存集合

db.goods.insert([   { "_id" : 1, "sku" : "almonds", description: "product 1", "instock" : 120 },   { "_id" : 2, "sku" : "bread", description: "product 2", "instock" : 80 },   { "_id" : 3, "sku" : "cashews", description: "product 3", "instock" : 60 },   { "_id" : 4, "sku" : "pecans", description: "product 4", "instock" : 70 },   { "_id" : 5, "sku": null, description: "Incomplete" },   { "_id" : 6 }])

需求:查询订单及对应商品的库存

如果 Mysql实现:

select 	order._id,	order.goodsName,  order.price,  order.quantity,  good.instock  from orders order left join goods good on order.goodsName = good.sku
//测试数据-订单db.orders.insert([   { "_id" : 1, "goodsName" : "almonds", "price" : 12, "quantity" : 2 },   { "_id" : 2, "goodsName" : "pecans", "price" : 20, "quantity" : 1 },   { "_id" : 3  }])//测试数据-商品库存db.goods.insert([   { "_id" : 1, "sku" : "almonds", description: "product 1", "instock" : 120 },   { "_id" : 2, "sku" : "bread", description: "product 2", "instock" : 80 },   { "_id" : 3, "sku" : "cashews", description: "product 3", "instock" : 60 },   { "_id" : 4, "sku" : "pecans", description: "product 4", "instock" : 70 },   { "_id" : 5, "sku": null, description: "Incomplete" },   { "_id" : 6 }])db.orders.aggregate([   {     $lookup:       {         from: "goods",//来自goods 表         localField: "goodsName", //拿那个字段去做对比         foreignField: "sku",//对比 sku 字段         as: "goodsObj" // 同 Mysql As 用法,用于展示联查的对象数据       }  }])

5.0 更新操作符

##### 5.1 $inc

$inc](https://www.docs4dev.com/docs/zh/mongodb/v3.6/reference/reference-operator-update-inc.html#up._S_inc)运算符使字段增加指定值,并具有以下形式:

{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }

说明:

$inc运算符接受正值和负值。

​ 如果该字段不存在,则$inc创建该字段并将该字段设置为指定的值。

​ 在值为空的字段上使用$inc运算符将产生错误。

$inc是单个文档中的原子操作。

//准备测试数据db.testDate.insert(    {        _id: 1,        status: "a",        lastModified: ISODate("2013-10-02T01:11:18.965Z")    })db.testDate.find()//修改时间为当前时间db.testDate.update({"_id":1},{$currentDate:{lastModified:true}})//不存在的字段会自动 添加新字段并插入新值db.testDate.update({"_id":1},{$currentDate:{newTime:true}})
5.2 $min
  • $min
    
    • $min将字段的值更新为指定的值,如果指定的值小于当前值那么修改,否则不修改。
{ $min: { <field1>: <value1>, ... } }

要在嵌入式文档或数组中指定<field>,请使用dot notation

说明:

如果该字段不存在,则$min运算符将该字段设置为指定的值。

为了比较不同类型的值(例如数字和空值),$min使用BSON 比较 Sequences

5.1 管道 agreegate

聚合管道是 MongoDB 2.2版本引入的新功能。它由阶段(Stage)组成,文档在一个阶段处理完毕后,聚合管道会把处理结果传到下一个阶段。

聚合管道功能:

  • 对文档进行过滤,查询出符合条件的文档
  • 对文档进行变换,改变文档的输出形式

管道属于一种聚合方式,mongodb 一共提供了三种 聚合数据的方式:

  1. 聚合管道 - Agreegation Pipeline
  2. 单目的聚合操作 - Single Purpose Aggreation Operation
  3. MapReduce 编程模型

每个阶段用**阶段操作符(Stage Operators)定义,在每个阶段操作符中可以用表达式操作符(Expression Operators)**计算总和、平均值、拼接分割字符串等相关操作,直到每个阶段进行完成,最终返回结果,返回的结果可以直接输出,也可以存储到集合中。

5.1.1 $project

🤩首先需要先熟悉 $project 操作符的使用,它主要用于添加或删除文档中的字段,案例如下:

//准备测试数据db.testArticle.insertMany([    {        "_id": ObjectId("58e1d2f0bb1bbc3245fa7570"),        "title": "MongoDB Aggregate",        "author": "liruihuan",        "tags": ['Mongodb', 'Database', 'Query'],        "pages": 5,        "time": ISODate("2017-04-09T11:42:39.736Z")    },    {        "_id": ObjectId("58e1d2f0bb1bbc3245fa7571"),        "title": "MongoDB Index",        "author": "liruihuan",        "tags": ['Mongodb', 'Index', 'Query'],        "pages": 3,        "time": ISODate("2017-04-09T11:43:39.236Z")    },    {        "_id": ObjectId("58e1d2f0bb1bbc3245fa7572"),        "title": "MongoDB Query",        "author": "eryueyang",        "tags": ['Mongodb', 'Query'],        "pages": 8,        "time": ISODate("2017-04-09T11:44:56.276Z")    }])

控制 _id 不返回,只返回 title,pages

aggregate 就是mongodb 的管道的用法,一个管道可以有多个阶段(Stage)

//不返回 _id,返回 title,pagesdb.testArticle.aggregate([{    $project: {        _id: 0,        title: 1,        pages: 1    }}])结果:MongoDB Aggregate	5MongoDB Index	3MongoDB Query	8
5.1.2 $add 实现对数据新增 并重命名为 新的字段
//把pages ,都➕10,并命名为 新字段 new_pagesdb.testArticle.aggregate(    [        {            $project: {                _id: 0,                title: 1,                pages: 1,                new_pages: {                    $add: ["$pages", 10]                }            }        }    ])//结果MongoDB Aggregate	5	15MongoDB Index	3	13MongoDB Query	8	18
5.1.2 $group 实现 分组计算每个作者的文章数量
//得到每个作者的文章数db.testArticle.aggregate(    [        {            $group: {                _id: "$author",                total: {                    $sum: 1                }            }        }    ])
5.1.3 $sort 按时间排序
//按文章发布时间排序,, 1:降序 -1:升序db.testArticle.aggregate([    {        $sort: {            time:  - 1        }    }])
5.1.4 $sort,$limit 多阶段实现先排序后限制返回数量
//先排序,再控制返回条数db.testArticle.aggregate([    {        $sort: {            time: - 1        }    },    {        $limit: 1    }])
5.1.5 $unwind 按文档中数组的个数 拆分为多条数据

注🤓:

  • $unwind 参数数组字段为空或不存在时,待处理的文档将会被忽略,该文档将不会有任何输出
  • $unwind 参数不是一个数组类型时,将会抛出异常
  • $unwind 所作的修改,只用于输出,不能改变原文档
//拆分数组成为 多条数据db.testArticle.aggregate([    {        $match: {            "title": "MongoDB Query"        }    },    {        $unwind: "$tags"    }])

5.2 聚合管道查询优化

默认情况下,整个集合作为聚合管道的输入,为了提高处理数据的效率,可以使用一下策略:

  • 将 $match 和 $sort 放到管道的前面,可以给集合建立索引,来提高处理数据的效率。
  • 可以用 $match、$limit、$skip 对文档进行提前过滤,以减少后续处理文档的数量。

当聚合管道执行命令时,MongoDB 也会对各个阶段自动进行优化,主要包括以下几个情况:

  1. $sort + $match 顺序优化

如果 $match 出现在 $sort 之后,优化器会自动把 $match 放到 $sort 前面

\2. $skip + $limit 顺序优化

如果 $skip 在 $limit 之后,优化器会把 $limit 移动到 $skip 的前面,移动后 $limit的值等于原来的值加上 $skip 的值。

例如:移动前:{$skip: 10, $limit: 5},移动后:{$limit: 15, $skip: 10}

5.3 单目聚合操作

//查询作者是 xyz 的文章数量db.articles.count({"author":"xyz"})//查询 去重复后的 作者列表db.articles.distinct("author")

参考文档:https://blog.csdn.net/weixin_45958024/article/details/103928885

https://www.docs4dev.com/docs/zh/mongodb/v3.6/reference/reference-operator-projection-positional.html#proj.S

https://www.runoob.com/mongodb/mongodb-operators-type.html

https://www.cnblogs.com/xuliuzai/p/10055535.html

https://www.cnblogs.com/yunlongaimeng/p/11460291.html

更多参考:https://www.docs4dev.com/docs/zh/mongodb/v3.6/reference/

0

评论区