Mongodb

中文文档:https://docs.mongoing.com/mongodb-crud-operations/insert-documents

命令文档:https://www.mongodb.com/docs/v4.2/reference/operator/query/

1、数据库

# 查看当前数据库
db

# 切换数据库,如果数据库不存在则自动创建
use <数据库名称>

# 删除当前 use 的数据库
db.dropDatabase()

# 数据备份
mongodump --db <database_name> --out <backup_directory>

2、集合

MongoDB将文档存储在集合中。集合类似于关系数据库中的表

创建集合

  • 显式创建

    db.createCollection( <name>,  
       {   
         // 创建一个有大小限制的集合  
         capped: <boolean>,  
         // 是否自动为每个文档的_id字段创建索引  
         autoIndexId: <boolean>,  
         // 有大小限制的集合的最大字节大小  
         size: <number>,  
         // 有大小限制的集合中允许的最大文档数  
         max: <number>,  
         // 存储引擎的配置选项  
         storageEngine: <document>,  
         // 验证器,用于确保插入或更新的文档满足指定的条件  
         validator: <document>,  
         // 验证器操作级别的选项:"moderate""strict",或 "ruthless"  
         validationLevel: <string>,  
         // 当文档不满足验证器条件时采取的操作:"error""warn"  
         validationAction: <string>,  
         // 索引选项的默认值  
         indexOptionDefaults: <document>,  
         // 视图所基于的集合名称  
         viewOn: <string>,  
         // 从数据到视图的转换过程  
         pipeline: <pipeline>,  
         // 集合的排序规则  
         collation: <document>,  
         // 写入关注点,即确认写操作完成之前所需满足的条件  
         writeConcern: <document>  
       }   
    )
  • 自动创建

    db.myCollection2.insertOne( {  x: 1 }  )

文档验证

默认情况下,集合不要求其文档具有相同的模式。也就是说,单个集合中的文档不需要具有相同的字段集,并且字段的数据类型可以在集合中的不同文档之间有所不同。

但是,从MongoDB 3.2开始,您可以在更新和插入操作期间对集合强制执行文档验证规则。有关详细信息,请参见模式验证

文档验证需要在创建文档的时候指定,如下:

db.createCollection("students", { 
   validator: { 
      $jsonSchema: { 
         bsonType: "object",
         required: [ "name", "year"],
         properties: { 
            name: { 
               bsonType: "string",
               description: "must be a string and is required"
            } ,
            year: { 
               bsonType: "int",
               minimum: 2017,
               maximum: 3017,
               description: "must be an integer in [ 2017, 3017 ] and is required"
            } ,
            address: { 
               bsonType: "object",
               required: [ "city" ],
               properties: { 
                  street: { 
                     bsonType: "string",
                     description: "must be a string if the field exists"
                  } ,
                  city: { 
                     bsonType: "string",
                     "description": "must be a string and is required"
                  } 
               } 
            } 
         } 
      } 
   } 
} )

也可以使用如下方式创建

db.createCollection( "contacts",
   {  validator: {  $or:
      [
         {  phone: {  $type: "string" }  } ,
         {  email: {  $regex: /@mongodb\.com$/ }  } ,
         {  status: {  $in: [ "Unknown", "Incomplete" ] }  } 
      ]
   } 
}  )

3、文档

MongoDB文档由字段和值对组成,并具有以下结构:

var mydoc = { 
    _id: ObjectId("5099803df3f4948bd2f98391"),
    name: {  first: "Alan", last: "Turing" } ,
    birth: new Date('Jun 23, 1912'),
    death: new Date('Jun 07, 1954'),
    contribs: [ "Turing machine", "Turing test", "Turingery" ],
    views : NumberLong(1250000)
} 

字段名称

  • 字段名称_id保留用作主键;它的值在集合中必须是唯一的,不可变的,并且可以是数组以外的任何类型。如果插入的文档省略了该_id字段,则MongoDB驱动程序会自动为该_id字段生成一个ObjectId

  • 字段名称不能包含null字符。

  • 顶级字段名称不能以美元符号($)字符开头。

数组

要通过从零开始的索引位置指定或访问数组的元素,请将数组名称与点(.)和从零开始的索引位置连接起来,并用引号引起来:

{ 
   ...
   contribs: [ "Turing machine", "Turing test", "Turingery" ],
   ...
} 

要指定contribs数组中的第三个元素,请使用点符号"contribs.2"

4、CRUD

文档插入

插入文档

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

插入多个文档

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" }  } 
])

文档查询

命令文档:https://www.mongodb.com/docs/v4.2/reference/operator/query/

查询所有

db.inventory.find( { }  )

等值查询

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

in 查询

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

and 查询

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

or 查询

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

多条件查询

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

查询数组

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

查询完全等于的数组

db.inventory.find( {  tags: ["red", "blank"] }  )

查询包含内容的数组,不区分顺序

db.inventory.find( {  tags: {  $all: ["red", "blank"] }  }  )

# 等价于
db.inventory.find( {  $and: [ {  tags: "red" } , {  tags: "blank" }  ] }  )

查询包含内容的数组

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

多条件查询

# 单个元素同时满足大于15并且小于20,或者一个元素满足大于15,另外一个元素小于20的所有文档
db.inventory.find( {  dim_cm: {  $gt: 15, $lt: 20 }  }  )

# 数组中最少一个元素同时满足所有的查询条件
db.inventory.find( {  dim_cm: {  $elemMatch: {  $gt: 22, $lt: 30 }  }  }  )

通过数组下标查询

# 数组字段dim_cm中第二个元素大于25的所有文档
db.inventory.find( {  "dim_cm.1": {  $gt: 25 }  }  )

通过数组长度查询

db.inventory.find( {  "tags": {  $size: 3 }  }  )

查询嵌套文档

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" } 
]);
# 下面的案例返回inventory集合中size字段的值等于文档{  h: 14, w: 21, uom: "cm" } 的所有文档
db.inventory.find( {  size: {  h: 14, w: 21, uom: "cm" }  }  )

# 但如果调换了顺序则查询不到
db.inventory.find(  {  size: {  w: 21, h: 14, uom: "cm" }  }   )
# 可以通过如下方式进行嵌套查询
db.inventory.find( {  "size.uom": "in" }  )

db.inventory.find( {  "size.h": {  $lt: 15 }  }  )

db.inventory.find( {  "size.h": {  $lt: 15 } , "size.uom": "in", status: "D" }  )

更新文档

更新命令文档:https://www.mongodb.com/docs/upcoming/reference/operator/update/set/#up._S_set

db.inventory.insertMany( [
   {  item: "canvas", qty: 100, size: {  h: 28, w: 35.5, uom: "cm" } , status: "A" } ,
   {  item: "journal", qty: 25, size: {  h: 14, w: 21, uom: "cm" } , status: "A" } ,
   {  item: "mat", qty: 85, size: {  h: 27.9, w: 35.5, uom: "cm" } , status: "A" } ,
   {  item: "mousepad", qty: 25, size: {  h: 19, w: 22.85, uom: "cm" } , status: "P" } ,
   {  item: "notebook", qty: 50, size: {  h: 8.5, w: 11, uom: "in" } , status: "P" } ,
   {  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" } ,
   {  item: "sketchbook", qty: 80, size: {  h: 14, w: 21, uom: "cm" } , status: "A" } ,
   {  item: "sketch pad", qty: 95, size: {  h: 22.85, w: 30.5, uom: "cm" } , status: "A" } 
] );

更新单个文档

db.inventory.updateOne(
    {  item: "paper" } ,
    { 
        $set: {  "size.uom": "cm", status: "P" } , 
        $currentDate: {  lastModified: true } 
    } 
)
  • 使用$set 运算符将size.uom字段的值更新为“ cm”,将状态字段的值更新为“ P”
  • 使用$currentDate运算符将lastModified字段的值更新为当前日期。 如果lastModified字段不存在,则$currentDate将创建该字段

更新多个文档

db.inventory.updateMany( 
    {  "qty": {  $lt: 50 }  } ,
    {   
        $set: {  "size.uom": "in", status: "P" } , 
        $currentDate: {  lastModified: true }   
    } 
)

替换文档

db.inventory.replaceOne(
   {  item: "paper" } ,
   {  item: "paper", instock: [ {  warehouse: "A", qty: 60 } , {  warehouse: "B", qty: 40 }  ] } 
)

直接将 item 等于 paper 的文档内容替换成新的

删除文档

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: "P" } ,
   {  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.deleteMany({ } )

删除单个文档

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

批量操作

  • 有序操作:MongoDB串行地执行操作。 如果在某个单独的写操作的处理过程中发生错误,MongoDB将直接返回而不再继续处理列表中任何剩余的写操作
  • 无序操作:MongoDB可以并行地执行操作,但是不能保证此行为。 如果某个单独的写操作的处理过程中发生错误,MongoDB将继续处理列表中剩余的写操作

bulkWrite()方法

bulkWrite() 支持如下操作:

  • insertOne
  • updateOne
  • updateMany
  • replaceOne
  • deleteOne
  • deleteMany
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" : { 

   } 
} 

5、springboot集成

1、导入依赖

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-data-mongodb</artifactId>  
</dependency>

2、编写实体类

import org.springframework.data.annotation.Id;  
import org.springframework.data.mongodb.core.mapping.Document;  

@Document(collection = "people")  
public class Person {   
    @Id  
    private String id;  
    private String name;  
    private int age;  

    // 省略getter和setter方法  
} 

3、创建 mapper 接口

import org.springframework.data.mongodb.repository.MongoRepository;  

public interface PersonRepository extends MongoRepository<Person, String> {   
} 

4、实现 crud

import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.stereotype.Service;  

@Service  
public class PersonService {   
    @Autowired
    private final PersonRepository personRepository;   

    public void savePerson(Person person) {   
        personRepository.save(person);  
    }   

    public void deletePerson(String id) {   
        personRepository.deleteById(id);  
    }   

    public Person findPersonById(String id) {   
        return personRepository.findById(id).orElse(null);  
    }   

    public List<Person> getAllPeople() {   
        return personRepository.findAll();  
    }   
} 

实现复杂查询

@Service  
public class PersonService {   

    @Autowired  
    private MongoTemplate mongoTemplate;  

    public List<Person> findPeopleAgeGreaterThan18() {   
        Query query = new Query();  
        query.addCriteria(Criteria.where("age").gt(18).and("name").is("zhangsan"));  
        return mongoTemplate.find(query, Person.class);  
    }  
} 

也可以在接口中用注解查询

@Repository  
public interface PersonRepository extends MongoRepository<Person, String> {   
    @Query("{ 'age': { $gt: ?0} } ")  
    List<Person> findByAgeGreaterThan(int age);  
} 

聚合管道

@Service  
public class PersonService {   

    @Autowired  
    private MongoTemplate mongoTemplate;  

    public AggregationResults<Person> findPeopleByAgeRange(int minAge, int maxAge) {   
        AggregationOperation match = Aggregation.match(Criteria.where("age").gte(minAge).lte(maxAge));  
        AggregationOperation group = Aggregation.group("age").count().as("count");  
        Aggregation aggregation = Aggregation.newAggregation(match, group);  
        return mongoTemplate.aggregate(aggregation, Person.class);  
    }   
}