MongoDB入门系列 ===; 基本操作:增删改查

Posted 刘翾

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MongoDB入门系列 ===; 基本操作:增删改查相关的知识,希望对你有一定的参考价值。

全系列目录

文章目录

1. 数据库

1.1 创建数据库

语法: use DATABASE_NAME

> use gkd
switched to db gkd

但如果不插入数据, 数据库是显示不出来的.

db.集合名(表名).insert(key: value)

1.2 删除数据库

> use 数据库名
> db.dropDatabase()

2. 集合(表)

2.1 创建集合

语法:

db.createCollection(name 集合名, options 可选参数)

options可选参数表格

字段类型描述
capped布尔 (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。
size数值 (可选)为固定集合指定一个最大值(以字节计)。如果 capped 为 true,也需要指定该字段。
max数值 (可选)指定固定集合中包含文档的最大数量。

详细参数列表请参考 https://docs.mongodb.com/manual/reference/method/db.createCollection/index.html

// 例1
db.createCollection("gkd",  capped : true, size : 1024  )

但如果没有特殊要求, 没有必要主动输入命令创建集合(表). 在我们插入数据的时候如果系统没有检测到表, 则会自动创建.

// 例2
 // 创建gkd表, 插入数据
 db.gkd.insert("name" : "菜鸟教程") 
 
 // 查看集合
 show collections

2.2 删除集合

// 删除集合
db.集合名.drop()

删除成功返回true


3. 文档(row)

3.1 插入文档

// 提到过还几次了
db.集合名.insert();

如果想一次插入多条数据, 例

db.集合名.insert([key: value, key, value])

3.2 查询文档

命令:

db.集合名.find(query, projection)
参数类型描述
querydocument可选, 查询条件, 如果要查询全部数据, 可忽略该参数或传递 (空文档)
projectiondocument可选, 指定要在与query匹配的文档中返回的字段(类似select). 如果要查询全部数据, 可忽略该参数

3.2.1 projection介绍

这个参数差不多相当于mysql里的select, 下面是一个例子

// 插入一条文档
> db.gkd.insert(a: 1, b: 2)

// 查询全部文档
> db.gkd.find()
 "_id" : ObjectId("5c318021a92a4958ddb16ae4"), "a" : 1, "b" : 2 

// 选择特定参数查询
> db.gkd.find(, a: true)
 "_id" : ObjectId("5c318021a92a4958ddb16ae4"), "a" : 1 


// 也可以采用链式调用
> db.gkd.find().projection(a: true)
// 返回结果同上

注:

  1. projection参数key: value里面的value, 也可以传1或者0, 1表示true, 0表示false
  2. 除非显示指定"_id": false, 否则它默认返回

3.2.2 查询运算符介绍

如果我们想要查一个值是否符合某个条件的时候, 就需要用到查询运算符. 例:

// 先插入3条数据, 接下来我想找到a大于等于2
db.gkd.insert([a: 1, a: 2, a: 3]);

// 可以看到a的值为一个对象, $gte代表大于等于
db.gkd.find(a: $gte: 2)

// 组合筛选, 如果我想要匹配大于1小于3
db.gkd.find(a: $gt: 1, $lt: 3)

3.2.2.1 运算符

名字描述
$eq等于
$gt大于
$gte大于等于
$in匹配数组中指定的任何值
$lt小于
$lte小于等于
$ne匹配不等于指定值的值
$nin匹配不存在数组中指定的任何值.
$exists匹配具有指定字段的文档(row)
$type匹配字段是指定类型的文档(row)

还有很多运算符不一一介绍, 只挑选了一些常用的列了出来, 详细请参看官方文档:
https://docs.mongodb.com/manual/reference/operator/query/#query-selectors

3.2.3 查询数组

有3个运算符需要介绍一下, 分别是$in. $all. $size

  1. $in 只要包含了值就匹配成功
    例:
// 我们先插入两条数据
> db.gkd.insert(b: [1])
> db.gkd.insert(b: [1, 2, 3])


> db.gkd.find(b: $in: [1,2])
 "_id" : ObjectId("5c318d5da92a4958ddb16ae5"), "b" : [ 1, 2, 3 ] 
 "_id" : ObjectId("5c319ed7a92a4958ddb16ae6"), "b" : [ 1 ] 
  1. $all指定的值必须要全部包含
// 用上个例子的数据
> db.gkd.find(b: $all: [1,2])
 "_id" : ObjectId("5c318d5da92a4958ddb16ae5"), "b" : [ 1, 2, 3 ] 
  1. $size数组长度匹配
// 用第一个例子的数据
> db.gkd.find(b: $size: 3)
 "_id" : ObjectId("5c318d5da92a4958ddb16ae5"), "b" : [ 1, 2, 3 ] 

3.2.4 正则匹配查询

mongodb还支持正则的查询, 关于正则详细规则, 可以参考我的这篇文章:
https://blog.csdn.net/c_kite/article/details/53959534
下面举个例子:

// 插入两条数据
 > db.gkd.insert([item: "liu", item: "xuan"])

// 匹配n结尾的的item文档
> db.gkd.find(item: /n$/)
 "_id" : ObjectId("5c31a123a92a4958ddb16ae8"), "item" : "xuan" 

3.2.5 限制条件

3.2.5.1 排序sort

注意官方提示: 除非指定sort()方法或使用$ near运算符,否则MongoDB不保证查询结果的顺序

例:

// 插入一些数据
> db.gkd.insert([a: 1, b: "xuan", a: 2, a: 3])

// 解释: 查找含有字段a的文档, 并且按照字段a进行升序排列, 1为升序, -1位降序
> db.gkd.find(a: $exists: true).sort(a: 1)
 "_id" : ObjectId("5c318558a56d67305c34fb80"), "a" : 1 
 "_id" : ObjectId("5c318558a56d67305c34fb81"), "a" : 2 
 "_id" : ObjectId("5c318558a56d67305c34fb82"), "a" : 3 

3.2.5.2 限制提取数量limit

db.gkd.find().limit(5); // 限制取5条数据

3.2.5.3 跳过数据skip

skip()方法控制结果集的起始点。以下操作将跳过gkd集合中的前5个文档并返回所有剩余文档

db.gkd.find().skip(5)

skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit()

3.2.6 聚合 aggregate

计算集合或视图中数据的聚合值, 类似于sql的count,语法:

db.collection.aggregate(pipeline, options)
参数类型描述
pipelinearray一系列数据聚合操作或阶段
optionsdocument可选, 一些可选参数

options可以包含以下的值

字段类型描述
explainboolean可选, 该操作返回带有文档的游标,该文档包含有关聚合管道处理的详细信息
allowDiskUseboolean可选, 允许写入临时文件。设置为true时,聚合操作可以将数据写入dbPath目录中的_tmp子目录
cursordocument可选的, 指定游标的初始批处理大小

只列举了少量参数, 更多详情请参见
https://docs.mongodb.com/manual/reference/method/db.collection.aggregate/index.html

在mongo shell中,如果从db.collection.aggregate()返回的游标没有使用var关键字分配给变量,则mongo shell会自动迭代光标20次

先看一个简单的例子:

 // 数据存在集合gkd中
 _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 
 _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 
 _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 
 _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 
 _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 

// 输入聚合命令
db.gkd.aggregate([
                      $match:  status: "A"  ,
                      $group:  _id: "$cust_id", total:  $sum: "$amount"   ,
                      $sort:  total: -1  
])

// 返回
 "_id" : "xyz1", "total" : 100 
 "_id" : "abc1", "total" : 75 

解释: 聚合操作选择状态等于“A”的文档,按cust_id字段对匹配文档进行分组,并从amount字段的总和计算每个cust_id字段的总数,并按降序对总字段对结果进行排序

3.2.6.1 pipeline常用参数介绍

名字描述
$match用于过滤数据,只输出符合条件的文档, $match使用MongoDB的标准查询操作
$limit用来限制MongoDB聚合管道返回的文档数
$skip在聚合管道中跳过指定数量的文档,并返回余下的文档
$group将集合中的文档分组,可用于统计结果
$sort将输入文档排序后输出
$lookup将两个集合连接起来
$unwind从输入文档解构数组字段以输出每个元素的文档(类似于js的解析异构, 下面有例子)
3.2.6.1.1 $lookup例子

语法:


   $lookup:
     
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     

参数描述
from指定要连接的数据库
localField当前库对应的字段
foreignField另一个库对应的字段
as新字段名称

例1 简单使用

// orders表插入数据
db.orders.insert([
    "_id" : 1, "item" : "almonds", "price" : 12, "quantity" : 2 ,
    "_id" : 2, "item" : "pecans", "price" : 20, "quantity" : 1 ,
    "_id" : 3  
])

// inventory库插入数据
db.inventory.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: "inventory", 
         localField: "item",
         foreignField: "sku",
         as: "inventory_docs"
       
  
])

// 查看结果
db.orders.find()


   "_id" : 1,
   "item" : "almonds",
   "price" : 12,
   "quantity" : 2,
   "inventory_docs" : [
       "_id" : 1, "sku" : "almonds", "description" : "product 1", "instock" : 120 
   ]


   "_id" : 2,
   "item" : "pecans",
   "price" : 20,
   "quantity" : 1,
   "inventory_docs" : [
       "_id" : 4, "sku" : "pecans", "description" : "product 4", "instock" : 70 
   ]


   "_id" : 3,
   "inventory_docs" : [
       "_id" : 5, "sku" : null, "description" : "Incomplete" ,
       "_id" : 6 
   ]

例2: 如果要聚合数组怎么办, 需要用到下一小节讲的$unwind, 可以先看一下

// orders 库有如下的数据
 "_id" : 1, "item" : "MON1003", "price" : 350, "quantity" : 2, "specs" :
[ "27 inch", "Retina display", "1920x1080" ], "type" : "Monitor" 

// inventory 库有如下的数据
 "_id" : 1, "sku" : "MON1003", "type" : "Monitor", "instock" : 120,
"size" : "27 inch", "resolution" : "1920x1080" 
 "_id" : 2, "sku" : "MON1012", "type" : "Monitor", "instock" : 85,
"size" : "23 inch", "resolution" : "1280x800" 
 "_id" : 3, "sku" : "MON1031", "type" : "Monitor", "instock" : 60,
"size" : "23 inch", "display_type" : "LED" 

// 连接
db.orders.aggregate([
   
      $unwind: "$specs" // 拆分specs字段
   ,
   
      $lookup:
         
            from: "inventory",
            localField: "specs",
            foreignField: "size",
            as: "inventory_docs"
        
   ,
   
      $match:  "inventory_docs":  $ne: []   // 匹配inventory_docs不为空的
   
])

// 返回结果

   "_id" : 1,
   "item" : "MON1003",
   "price" : 350,
   "quantity" : 2,
   "specs" : "27 inch",
   "type" : "Monitor",
   "inventory_docs" : [
      
         "_id" : 1,
         "sku" : "MON1003",
         "type" : "Monitor",
         "instock" : 120,
         "size" : "27 inch",
         "resolution" : "1920x1080"
      
   ]

例3 指定多个连接条件 (信息量是挺多的… 慢慢看吧…)

如果想要除了相等连接之外, 还想要有其他的判断条件, 例如 ‘小于’ 之类的就需要用到下面这个语法
语法:


   $lookup:
     
       from: <collection to join>,
       let:  <var_1>: <expression>, …, <var_n>: <expression> ,
       pipeline: [ <pipeline to execute on the collection to join> ],
       as: <output array field>
     

字段描述
from指定数据库
let可选, 指定要在管道字段阶段中使用的变量
pipeline执行各种操作写在这里
as指定要添加到输入文档的新数组字段的名称
// 用法
// orders表插入数据
db.orders.insert([
   "_id" : 1, "item" : "almonds", "price" : 12, "ordered" : 2 ,
   "_id" : 2, "item" : "pecans", "price" : 20, "ordered" : 1 ,
   "_id" : 3, "item" : "cookies", "price" : 10, "ordered" : 60 
])

// warehouses表插入数据
db.warehouses.insert([
   "_id" : 1, "stock_item" : "almonds", warehouse: "A", "instock" : 120 ,
   "_id" : 2, "stock_item" : "pecans", warehouse: "A", "instock" : 80 ,
   "_id" : 3, "stock_item" : "almonds", warehouse: "B", "instock" : 60 ,
   "_id" : 4, "stock_item" : "cookies", warehouse: "B", "instock" : 40 ,
   "_id" : 5, "stock_item" : "cookies", warehouse: "A", "instock" : 80 
])

// 关于$expr参数的详细介绍 => https://docs.mongodb.com/manual/reference/operator/query/expr/#op._S_expr
// 关于$project参数的详细介绍 => https://docs.mongodb.com/manual/reference/operator/aggregation/project/index.html

// 简单总结$expr和$project的含义(太多了.... 写不完了, 详情请参考上面链接)
// $expr:  在$expr内部可以使用聚合表达式, 内部可以使用let参数中定义的变量, 要采用'$$name'形式
// $project: 类似于find内的projection, 可以过滤参数
db.orders.aggregate([
   
      $lookup:
         
           from: "warehouses",
           let:  order_item: "$item", order_qty: "$ordered" , // 定义两个变量
           pipeline: [
               $match: // 匹配query
                  $expr: // 访问变量, 愈合操作
                     $and: // 并操作
                       [
                          $eq: [ "$stock_item",  "$$order_item" ] , // warehouses.stock_item === orders.item
                          $gte: [ "$instock", "$$order_qty" ]  // warehouses.instock >= orders.ordered
                       ]
                    
                 
              ,
               $project:  stock_item: 0   // 0和false同样的意思, 过滤掉stock_item字段
           ],
           as: "stockdata" // 新字段名字叫做stockdata
         
    
])
3.2.6.1.2 $unwind例子

语法:


  $unwind:
    
      path: <field path>,
      includeArrayIndex: <string>,
      preserveNullAndEmptyArrays: <boolean>
    

参数类型描述
pathstring数组字段的字段路径。要指定字段路径,请在字段名称前加上美元符号$,并用引号括起来
includeArrayIndexstring可选, 用于保存元素的数组索引的新字段的名称。该名称不能以美元符号$开头
preserveNullAndEmptyArraysboolean可选, 如果为true,如果路径为null,missing或为空数组,$ unwind将输出文档。如果为false,则$ unwind在路径为null,missing或空数组时不输出文档
// 例
// gkd库里有条数据
 "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] 

// 使用聚合给拆开
db.gkd.aggregate( [  $unwind : "$sizes"  ] )

// 返回数据
 "_id" : 1, "item" : "ABC1", "sizes" : "S" 
 "_id" : 1, "item" : "ABC1", "sizes" : "M" 
 "_id" : 1, "item" : "ABC1", "sizes" : "L" 

更多参数点击这里: https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

3.2.6.1 常用表达式介绍

表达式描述
$sum计算总和
$avg计算平均值
$min获取集合中所有文档对应值得最小值
$max获取集合中所有文档对应值得最大值
$push在结果文档中插入值到一个数组中

更多参数点击这里: https://docs.mongodb.com/manual/reference/operator/aggregation/

3.3 更新文档

语法

db.collection.update(
   <query>,
   <update>,
   
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>,
     arrayFilters: [ <filterdocument1>, ... ]
   
)
参数类型描述
querydocument查询条件, 语法和find方法相同
updatedocumentupdate的对象和一些更新的操作符
upsertboolean可选。如果设置为true,则在没有文档与查询条件匹配时创建新文档。默认值为false,如果未找到匹配项,则不会插入新文档
multiboolean可选。如果设置为true,则更新符合查询条件的多个文档。如果设置为false,则更新一个文档。默认值为false
writeConcerndocument可选, 抛出异常的级别
collationdocument可选, collation允许用户为字符串比较指定特定于语言的规则,例如字母和重音标记的规则
arrayFiltersarray可选的。一组过滤文档,用于确定要为array字段上的更新操作修改哪些元素. 例: [ “x.a”: $gt: 85 , “x.b”: $gt: 80 ]
// 例:

  _id: 1,
  item: "TBD",
  stock: 0,
  info:  publisher: "1111", pages: 430 ,
  tags: [ "technology", "computer" ],
  ratings: [  by: "ijk", rating: 4 ,  by: "lmn", rating: 5  ],
  reorder: false



// 命令语句
db.books.update(
    _id: 1 ,
   
     $inc:  stock: 5 ,
     $set: 
       item: "ABC123",
       "info.publisher": "2222",
       tags: [ "software" ],
       "ratings.1":  by: "xyz", rating: 3 
     
   
)

// 结果

  "_id" : 1,
  "item" : "ABC123",
  "stock" : 5,
  "info" :  "publisher" : "2222", "pages" : 430 ,
  "tags" : [ "software" ],
  "ratings" : [  "by" : "ijk", "rating" : 4 ,  "by" : "xyz", "rating" : 3  ],
  "reorder" : false

我们可以看到如果想要修改数组中的某个值, 可以采用 a.b 的形式

3.3.1 $set

如果该字段不存在,$ set将添加具有指定值的新字段,前提是新字段不违反类型约束. 也就是说增加列的操作使用update操作也可以

3.3.2 $inc

我理解的意思是对于数字的增减. https://docs.mongodb.com/manual/reference/operator/update/inc/#up._S_inc

可以看下刚刚3.3节的例子, $inc: stock : 5, 最后的结果输出的事原来的stock(值为0) + 5 = 5

$inc只接受数字类型, 如果在原文档中不存在会创建一个

3.3.3 save()

save是替换和插入文档的整合, 如果文档不包含_id字段,则save()方法将调用insert()方法, 如果包含则调用update方法, 替换掉整条文档. 语法:

db.collection.save(
   <document>,
   
     writeConcern: <document>
   
)

// 例

// update
db.gkd.save(
    _id: ObjectId("5c34262c2b52c0876812847c"),
    asd: 'asd'
)

// insert
db.gkd.save(
    asd: 'asd'
)

3.4 删除文档

语法:

db.collection.remove(
   <query>,
   
     justOne: <boolean>,
     writeConcern: <document>,
     collation: <document>
   
)
参数类型描述
querydocument使用查询运算符指定删除条件。要删除集合中的所有文档,请传递空文档()
justOneboolean可选的。ture的话删除仅一个文档。省略默认值为false, 删除与删除条件匹配的所有文档

// 例

db.gkd.remove(
    likes: 
        $gte: 800
    
)

// 仅删除一个
db.gkd.remove(
    likes: 
        $gte: 800
    
, true)

以上是关于MongoDB入门系列 ===; 基本操作:增删改查的主要内容,如果未能解决你的问题,请参考以下文章

[MongoDB]增删改查

mongoose入门以及 mongoose 实现数据 的增删改查

MongoDB——MongoDB安装+增删改查操作

MongoDB——MongoDB安装+增删改查操作

Mybatis从入门到精通系列 13——基于注解配置的增删改查

ABP学习入门系列(展示实现增删改查)