资讯专栏INFORMATION COLUMN

开发者需要了解的MongoDB知识点

MartinDai / 2791人阅读

摘要:删除符合值为的第一条数据删除符合值为的所有数据值得一提的是,删除操作并不会改变的索引设置,即便删除了这个下的所有文档。因此这类批量执行指令是非原子性的。官方推荐使用前者。在设计数据模型时,要考虑根据不同情况选择适合的文档结构进行设计。

1. 基础概念 1.1 database

数据库,一个数据仓库可以包含多个集合

1.2 collection

集合,类似于关系数据库中的表。一个集合可以包含多个文档。

capped collection(限制集合):设定空间上线,循环写入,新数据覆盖旧数据

1.3 document

文档,一个文档保存着一份数据记录。

1.3.1 数据校验

一个集合下的文档,不会默认要求它们具有相同的数据模式。也就是说,同一个集合下的多个文档:1.字段可以不同;2.同名字段的类型可以不同;相反,如果对文档数据类型有要求,可以在创建集合时设置validator(例如使用JSON schema)来限制集合下文档的数据类别。

1.3.2 文档格式

文档使用BSON来存储,BSON是JSON的二进制表现形式,因此可以适应更多的数据类型。
存储在文档的数据格式,与JSON类似,以键值对的形式存储。
默认主键_id,为ObjectId类型。

2. 基本的CRUD方法 2.1 插入数据 2.1.1 单条插入

使用insert_one()方法

book = {
    "name": "computer_science",
    "page": 238,
}
result = db.books.insert_one(book)
_id = result.inserted_id    # 返回插入项的id,类型为ObjectId
2.1.2 多条插入

使用insert_many()方法

results = db.collection_name.insert_many([document1, document2, ...])
id_list = results.inserted_ids    # 返回插入项的id列表,列表元素为ObjectId
2.1.3 废弃的插入方法

从pymongo3.0版本开始,已经不推荐使用insert()方法插入数据,虽然它能同时满足单条或多条数据的处理需求。
官方建议使用insert_one()和insert_many()来执行替代操作

2.2 查询数据

假设预先执行了数据插入:

db.inventory.insert_many([
    {"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"}])
2.2.1 基本查询操作
2.2.1.1 查询所有数据

使用find()方法执行查询,返回游标cursor
查询所有记录时,find()内的filter参数为空

cursor = db.inventory.find({})

上述查询,类似于关系数据库SQL语句:

SELECT * FROM inventory
2.2.1.2 等价条件查询
cursor = db.inventory.find({"status": "D"})

上述查询语句,类似于关系数据库SQL语句:

SELECT * FROM inventory WHERE status = "D"
2.2.1.3 复合条件查询(使用查询操作符查询)

包含(IN)关系查询

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

上述查询语句,类似于关系数据库SQL语句:

SELECT * FROM inventory WHERE status in ("A", "D")

与(AND)关系查询

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

上述查询语句,类似于关系数据库SQL语句:

SELECT * FROM inventory WHERE status = "A" AND qty < 30

或(OR)关系查询

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

上述查询语句,类似于关系数据库SQL语句:

SELECT * FROM inventory WHERE status = "A" OR qty < 30

在查询中同时使用AND和OR

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

上述查询语句,类似于关系数据库SQL语句:

SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")
2.2.2 查询操作符

查询操作符定义了查询条件,如:大于、等于、小于等,以下是整理的查询操作符及说明:

比较操作符 说明
$eq 等于
$gt 大于
$gte 大于等于
$in 包含
$lt 小于
$lte 小于等于
$ne 不等于
$nin 不包含于
逻辑操作符 说明
$and
$not
$nor 或非
$or
元素操作符 说明
$exists 指定field存在
$type 指定field的type

查看field的type类型说明

其他操作符说明请见:Query and Projection Operators

2.2.3 嵌套文档查询

对于文档中存在的嵌套结构的查询,可以对文档中的嵌套结构进行 匹配查询 ,也可以对嵌套内容中的某个字段进行 嵌套字段查询

假设文档数据如下:

from bson.son import SON
db.inventory.insert_many([
    {"item": "journal", # 物品名称
     "qty": 25,    # 数量
     "size": SON([("h", 14), ("w", 21), ("uom", "cm")]), # 嵌套结构(高度,宽度,度量单位)
     "status": "A"}, # 状态
    {"item": "notebook",
     "qty": 50,
     "size": SON([("h", 8.5), ("w", 11), ("uom", "in")]),
     "status": "A"},
    {"item": "paper",
     "qty": 100,
     "size": SON([("h", 8.5), ("w", 11), ("uom", "in")]),
     "status": "D"},
    {"item": "planner",
     "qty": 75,
     "size": SON([("h", 22.85), ("w", 30), ("uom", "cm")]),
     "status": "D"},
    {"item": "postcard",
     "qty": 45,
     "size": SON([("h", 10), ("w", 15.25), ("uom", "cm")]),
     "status": "A"}])

对嵌套结构进行匹配查询

from bson.son import SON
cursor = db.inventory.find(
    {"size": SON([("h", 14), ("w", 21), ("uom", "cm")])})
# 上述查询语句中的filter条件,需要完全匹配嵌套文档中的内容,否则无法查询到相关记录。

对嵌套结构中的字段进行查询

mongo使用点表示法指定文档中的嵌套字段:"field.nested_field"

# 查询嵌套字段uom的值为cm的记录
cursor = db.inventory.find({"size.uom": "cm"})

# 使用操作符查询高度大于10的记录
cursor = db.inventory.find({"size.h": {"$gt": 10}})

# 多个字段的复合查询
cursor = db.inventory.find(
    {"size.h": {"$lt": 15}, "size.uom": "in", "status": "D"})
2.2.4 数组类型查询

假设向collection中插入如下数据

db.inventory.insert_many([
    {"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]}])

与2.2.3中嵌套文档查询类似,可以对整个数组进行 匹配查询 , 也可以对数组中的某个元素进行查询

匹配整个数组

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

查询数组中的某个元素

# 所有tags中包含red元素的数组都会被查询到
cursor = db.inventory.find({"tags": "red"})

# 对数组中某个元素进行条件查询
# dim_cm中任意一个元素大于25的记录查询
cursor = db.inventory.find({"dim_cm": {"$gt": 25}})

数组元素的复合条件查询

查询dim_cm中的某个元素能同时满足大于15小于20的查询条件的记录
或者 dim_cm中的一个元素大于15,并且存在另一个元素小于20的记录

#  这种查询是不限制单个数组元素的,多个数组元素分别满足查询条件亦可
cursor = db.inventory.find({"dim_cm": {"$gt": 15, "$lt": 20}})

若要指定数组中某一个元素满足多个查询条件,需要使用 __$elemMatch__操作符来进行查询

# 查询数组中存在某一个元素同时满足大于22并且小于30
cursor = db.inventory.find(
    {"dim_cm": {"$elemMatch": {"$gt": 22, "$lt": 30}}})

根据数组索引位置查询

查询dim_cm的第一个元素大于25的记录

cursor = db.inventory.find({"dim_cm.1": {"$gt": 25}})

根据数组长度查询

查询数组长度是否符合查询条件,需要使用 $size 操作符
查询所有tags长度等于3的的记录

cursor = db.inventory.find({"tags": {"$size": 3}})
2.2.5 数组内的嵌套文档查询

假设向collection中插入如下数据:

from bson.son import SON
db.inventory.insert_many([
    {"item": "journal",
     "instock": [
         SON([("warehouse", "A"), ("qty", 5)]),
         SON([("warehouse", "C"), ("qty", 15)])]},
    {"item": "notebook",
     "instock": [
         SON([("warehouse", "C"), ("qty", 5)])]},
    {"item": "paper",
     "instock": [
         SON([("warehouse", "A"), ("qty", 60)]),
         SON([("warehouse", "B"), ("qty", 15)])]},
    {"item": "planner",
     "instock": [
         SON([("warehouse", "A"), ("qty", 40)]),
         SON([("warehouse", "B"), ("qty", 5)])]},
    {"item": "postcard",
     "instock": [
         SON([("warehouse", "B"), ("qty", 15)]),
         SON([("warehouse", "C"), ("qty", 35)])]}])

可以看到instock数组内部每一个元素都是一个嵌套文档。对这类数据的查询方法,是2.2.3嵌套文档查询和2.2.4数组类型查询的结合。

对数组内某个嵌套文档进行 匹配查询

# 匹配查询对于嵌套文档内的field顺序有要求,
# 查询结果只展示与查询条件中field排列顺序相同的记录。
cursor = db.inventory.find(
    {"instock": SON([("warehouse", "A"), ("qty", 5)])})

对数组内的嵌套文档字段进行 条件查询

# 查询所有文档中,instock数组中至少有一个元素的qty值大于20的记录
cursor = db.inventory.find({"instock.qty": {"$lte": 20}})

对数组形式的嵌套文档按照 数组索引查询

# 查询所有文档中,instock数组的第0个嵌套文档元素中,qty的值小于等于20的所有记录
cursor = db.inventory.find({"instock.0.qty": {"$lte": 20}})

使用 $elemMatch 对数组内的某个嵌套文档进行复合查询

# 数组内的某个文档同时满足qty=5并且warehouse值为A的查询条件
cursor = db.inventory.find(
    {"instock": {"$elemMatch": {"qty": 5, "warehouse": "A"}}})

# 数组内的某个文档的qty值大于10并且小于等于20
cursor = db.inventory.find(
    {"instock": {"$elemMatch": {"qty": {"$gt": 10, "$lte": 20}}}})
2.2.6 指定查询结果返回的field

MonogDB返回的查询结果,默认包含文档中所有的field,使用者可以通过让mongo返回指定的field,来限制返回内容的数量。

查询表达式如下:

# 返回指定的field
cursor = db.inventory.find(
    {"status": "A"}, {"item": 1, "status": 1, "size.uom": 1})

# 不返回指定的field
cursor = db.inventory.find({"status": "A"}, {"size.uom": 0, "status": 0})

# 对于数组形式的field,指定只返回最后一个元素(使用$slice操作符)
cursor = db.inventory.find(
    {"status": "A"},
    {"instock": {"$slice": -1}})
2.2.7 查询空值和field是否存在

查询item为空或item字段不存在

cursor = db.inventory.find({"item": None})

只查询字段为空的记录
type值参照

# type值为10时表示的是null类型
cursor = db.inventory.find({"item": {"$type": 10}})

查询某字段不存在

# 查询所有文档中,没有item字段的记录
cursor = db.inventory.find({"item": {"$exists": False}})
2.3 更新数据

MongoDB提供了一系列的操作符来帮助完成文档数据更新,具体说明可查看链接:https://docs.mongodb.com/manu...

2.3.1 更新单个文档

使用pymongo的update_one方法

db.inventory.update_one(
    {"item": "paper"}, # filter筛选条件, 只更新符合该条件的第一条数据
    {"$set": {"size.uom": "cm", "status": "P"},
     "$currentDate": {"lastModified": True}}) # 数据更新表达式,使用$set操作符来更新数据
2.3.2 更新多个文档

使用pymongo的update_many()方法

db.inventory.update_many(
    {"qty": {"$lt": 50}}, # filter筛选条件,更新符合该条件的所有数据
    {"$set": {"size.uom": "in", "status": "P"},
     "$currentDate": {"lastModified": True}})# 数据更新表达式,同样使用$set操作符来更新数据
2.3.3 替换文档

使用pymongo的replace()方法

注:替换方法只替换除_id以外的其他字段

db.inventory.replace_one(
    {"item": "paper"}, # filter筛选条件,替换符合该条件的第一条数据
    {"item": "paper", # 替换后的文档数据
     "instock": [
         {"warehouse": "A", "qty": 60},
         {"warehouse": "B", "qty": 40}]})
2.3.4 upsert选项

不论是update_one()方法还是update_many()方法,亦或是replace_one()方法,都包含upsert:bool 选项,当upsert为True时,这些方法将具备在filter未筛选到文档时,执行文档插入的能力。

2.4 删除数据

pymongo提供了delete_one()和delete_many()两种方法执行删除操作。其中,delete_one()方法一次执行一条文档的删除任务,delete_manyI()可执行多条文档删除任务。

db.inventory.delete_one({"status": "D"}) # 删除符合status值为D的第一条数据
db.inventory.delete_many({"status": "A"}) # 删除符合status值为A的所有数据

值得一提的是,删除操作并不会改变collection的索引设置,即便删除了这个collection下的所有文档。

2.5 批量写入

pymongo提供了批量写入方法:bulk_write(),类似于redis中的pipe_line,它可以将多个写入操作作为一个list参数传入,然后一起执行。它支持insert、update、replace、delete的多种方法,以下是官方文档提供的示例:

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);
}
3. 数据模型 3.1 基础知识 3.1.1 灵活的模式

1)同一个集合下,不同文档的字段可以不一致;同一个集合下,不同文档的相同字段,类型可以不一致;
2)可以通过对一个文档的字段进行增删改操作,或是变更字段类型,来改变文档的结构。

3.1.2 文档结构

1) __嵌入式文档结构__,即在一个文档内,可以嵌套子文档内容,实现逻辑相关的数据结构嵌套组合。嵌套式文档结构如下:

# 用户信息表
{
    _id: ObjectId_1,
    username: "youjia",
    sex: "man",
    age: 29,
    contact: { # 嵌入式文档
        phone: 18195181469,
        email: "jia.you@shunwang.com",
    }
}

2) __引用式__,不同类型数据使用id引用进行关联,上例可变为:

# 用户表
{
    _id: ObjectId_1,
    username: "youjia",
    sex: "man",
    age: 29,

}

# 联系信息表(原嵌入式文档)
{
    _id: ObjectId_2,
    user_id: ObjectId_1, # 对应用户表_id
    phone: 18195181469,
    email: "jia.you@shunwang.com",
}
3.1.3 原子性的写入操作

1) 对一个文档的写入操作是原子性的,即使这个写入操作包含了对嵌套文档的数据写入。
2) 由于对嵌套文档的写入动作是原子性的,因此嵌套式的文档结构设计,更加促进了写入操作原子化,提高了写入效率和数据一致性。
3) 当执行类似updateMany等操作时,虽然只执行了一条指令,但其内部执行过程实际上包含了对多个文档的原子操作。因此这类批量执行指令是非原子性的。
4) 由于对多个文档的批量指令执行是非原子性的,因此在对多个文档进行写入操作时,写入任务可能与其他批量写入任务交叉。
5) 从MongoDB4.0开始,为了保证多文档写入/读取数据的一致性,加入了多表操作事务
6) 多表操作事务相比单表操作,会造成大的多的性能消耗,因此官方仍然认为,在多数情况下 __嵌入式文档结构是更好的选择__。

3.1.4 数据模型校验

官方提供了多种数据模型校验的方法,包括:1. JSON Schema校验,2. 查询表达式校验。官方推荐使用前者。
一个典型的JSON Schema语法示例:

db.createCollection("students", {
   validator: {
      $jsonSchema: {
         bsonType: "object",
         required: [ "name", "year", "major", "gpa" ],
         properties: {
            name: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            gender: {
               bsonType: "string",
               description: "must be a string and is not required"
            },
            year: {
               bsonType: "int",
               minimum: 2017,
               maximum: 3017,
               exclusiveMaximum: false,
               description: "must be an integer in [ 2017, 3017 ] and is required"
            },
            major: {
               enum: [ "Math", "English", "Computer Science", "History", null ],
               description: "can only be one of the enum values and is required"
            },
            gpa: {
               bsonType: [ "double" ],
               minimum: 0,
               description: "must be a double and is required"
            }
         }
      }
   }
})

关于JSON Schema的更详细信息,可参照网上教程:https://spacetelescope.github...

3.2 模型设计原则 3.2.1 设计原则概述

3.1.1中介绍了模型的两种设计结构:__嵌入式文档结构__,和 引用式 文档结构。在设计数据模型时,要考虑根据不同情况选择适合的文档结构进行设计。

3.2.1.1 选择嵌套式文档结构

以下情况下适合使用嵌入式文档结构:

1) 两类数据是一对一并且具有包含关系。例如:用户个人信息-用户联系信息
2) 两类数据时一对多关系,但是在应用过程中通常两类数据需要联合查询使用,使用“一”时通常会查询“多”。

嵌套式文档结构的优点:

嵌套式文档结构提供了更好的读性能,数据查询可在一个集合内完成而不必跨集合查询。

降低了数据写入消耗,数据不必多文档写入,一次数据写入任务可以在一个文档内完成,仅执行一次原子性操作。

注意:MongoDB默认限制单个文档大小最大为16MB,因此单个文档大小不能无限扩大。Mongo提供了其他大体量数据的存储方式:GridFS

3.2.1.2 选择引用式文档结构

以下情况适合使用引用式文档结构:

1) 当采用嵌套式文档结构时,被嵌套的数据会有大量重复,并且大量重复数据造成影响大于嵌套文档的优势时,选择引用式文档结构时更好的选择。
2) 要设计“多对多”关系时。
3) 为大型分层数据集建模时。

引用式文档的优点:

相比嵌套式结构,多组数据的关系更加解耦。

更适应多对多的关系场景。

3.2.1.3 模型设计中的其他考虑因素

原子性操作数量是影响数据库操作性能的主要因素之一,多数情况下,嵌入式文档结构可以有效降低数据库操作成本,提高性能。

多文档引用关系下的跨文档操作,会提高操作成本。

多文档数据操作,涉及到读写数据一致性问题,需要用到事务(4.0以后版本)。事务的使用会带来明显的性能消耗。

对读操作较多的文档设置索引可以提升查询性能,索引设置在查询较多的字段上,主键_id默认设置了索引。

索引对写操作的性能有影响。

索引会占用一定的数据空间,影响内存和磁盘的空间使用。

单个文档存储的数据量过大时,会影响数据库操作请求往返的时间和带宽消耗。

单个文档不要超过16MB,过于小的文档模型会浪费存储空间。

小文档可以通过缩短filed名称长度来降低存储空间消耗。

对于没有持久化需求的数据,可以设置集合属性为“限制集合capped collection”来控制集合大小。

4. 索引

对于查询需求较多的文档,可以通过在适合的字段建立索引来提高查询效率。但是对文档建立过多的索引,会影响写入效率,增加磁盘和内存的空间使用率。

4.1 索引类型 4.1.1 单字段索引

对文档内单个字段建立索引,称为单字段索引。适合对文档内单个字段有频繁查询请求的场景。

db.person.createIndex( {id_no: 1} )

{id_no: 1}代表升序索引,{id_no: -1}代表降序索引,在单字段索引类型下,升序与降序没有区别。

4.1.2 复合索引

复合索引是对多个字段联合创建一个索引。适合对文档内某些字段有频繁查询请求,以及查询与排序请求并存的业务场景。

db.person.createIndex( {age: 1, name: 1} )

创建符合索引时,field的顺序是有关系的。索引将按照第一个field进行升序/降序排列,在此基础上,再对第二个field进行升序/降序排列,以此类推。

4.1.3 多key索引

当索引的字段为数组时,创建出的索引称为多key索引,多key索引会为数组的每个元素建立一条索引,比如person表加入一个habbit字段(数组)用于描述兴趣爱好,需要查询有相同兴趣爱好的人就可以利用habbit字段的多key索引。

//文档格式
{"name" : "jack", "age" : 19, habbit: ["football, runnning"]}

// 自动创建多key索引
db.person.createIndex( {habbit: 1} )  
db.person.find( {habbit: "football"} )
4.2 索引属性 4.2.1 唯一索引

保证索引对应的字段不会出现相同的值,文档主键_id的索引,就是唯一索引。

4.2.2 TTL索引

可以针对某个时间字段,指定文档的过期时间(经过指定时间后过期 或 在某个时间点过期)

4.2.3 部分索引

只针对符合某个特定条件的文档建立索引,比如某字段值大于5,或者某字段值符合某正则表达式,才建立索引,注意:3.2版本才支持该特性.

4.2.4 稀疏索引

只针对存在索引字段的文档建立索引,可看做是部分索引的一种特殊情况

4.3 索引使用注意事项 4.3.1 创建索引

选择查询需求较多的文档创建索引;

文档中索引创建数量不宜过多,过多的索引会影响写入速度,占用磁盘和内存空间。

根据查询场景,选择合适的索引类型。

在已填满数据的集合里创建索引,要设置background选项为True,否则在创建过程中会阻塞所有对该集合的读写请求,直至索引创建完成。因此在已有数据的集合内创建索引时,要谨慎。

4.3.2 选择合适的索引

单字段索引

对文档内的某个字段有频繁的查询需求

对文档内的某个字段有频繁的排序需求

单字段索引创建,可以不关心索引是升序还是降序的,这对单字段索引没有影响

可以通过“点标法”对文档的内嵌文档中的字段建立索引

复合索引

对文档内的某些字段有频繁的查询需求,并且查询需求通常是针对多个字段同时进行的

对文档内的某些字段同时有查询和排序需求,并且查询排序需求通常是同时针对多个字段进行的

创建复合索引时,需根据查询场景选择各字段的索引是升序还是降序。例如:

# 创建索引
db.collection.create_index( { "x" : 1, "y" : -1 } )

# 支持下列查询/排序
db.collection.find().sort( { "x": 1, "y": -1 } )
db.collection.find().sort( { "x": -1, "y": 1 } )

# 对下列查询/排序,索引不生效
db.collection.find().sort( { "x": 1, "y": 1 } )

根据业务场景需求,选择合适的索引前缀(字段索引顺序),后缀的索引是在前缀索引的基础上建立的。前缀索引可以作为多带带的索引字段查询,但是后缀的索引不可以这样应用。例如:

# 创建索引
db.collection.create_index( { "x" : 1, "y" : 1 , "z": 1} )

# 支持对下列查询/排序场景
db.collection.find().sort({"x": 1})
db.collection.find().sort({"x": 1, "y": 1})
db.collection.find().sort({"x": 1, "z": 1}) # 效率较低
db.collection.find().sort({"x": 1, "y": 1, "z": 1})

# 不支持下列查询/排序场景
db.collection.find().sort({"y": 1})
db.collection.find().sort({"z": 1})
db.collection.find().sort({"y": 1, "z": 1})

多key索引

针对数组类型的field创建索引,即为多key索引,创建方式与单key索引一样,当field的数组元素为内嵌文档时,可以对内嵌文档的字段建立多key索引。

一个文档只允许存在一个多key索引。当此文档存在多个array类型的field时,只能针对其中一个field建立多key索引。

复合索引中,可以允许一个文档下存在一个多key索引,而不要求一定是某个field。例如:

# 创建复合索引
db.collection.create_index( { "x" : 1, "y" : 1 } )

# 索引支持的文档
{ "x" : 1, "y" : [1,2,3] }
{"x": [1,2,3], "y": 1}

# 不支持的情况
{"x": [1,2,3], "y": [1,2,3]}

可以对array内的嵌入式文档的某个field建立索引。例如:

# 文档结构
{
    "x": "test",
    "y": 1,
    "z": [
        {"a": 1, "b": "test"},
        {"a": 2, "b": "some"},
        ...
    ],
}

# 建立嵌入式文档的多key索引
db.collection_name.create_index({"z.a": 1, "z.b": -1})

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19345.html

相关文章

  • 小光光谈前端

    摘要:这个问题应该是百度或者知乎都能知道答案的,以上是自己亲身学习的一些途径方便少走一点弯路入门。 问题1:前端的学习路线 基础的html,css,js,推荐慕课网免费课程:前端工程师路径,极客学院免费课程:前端工程师路径 大概刷过就可以了,不用死记硬背某个知识点,css跟js还需要加深学习的,在实战过程中不懂就去查文档 基础的ps切图能力 慕课网ps基础课程 拥有自己的虚拟主机 传送...

    canopus4u 评论0 收藏0
  • 小光光谈前端

    摘要:这个问题应该是百度或者知乎都能知道答案的,以上是自己亲身学习的一些途径方便少走一点弯路入门。 问题1:前端的学习路线 基础的html,css,js,推荐慕课网免费课程:前端工程师路径,极客学院免费课程:前端工程师路径 大概刷过就可以了,不用死记硬背某个知识点,css跟js还需要加深学习的,在实战过程中不懂就去查文档 基础的ps切图能力 慕课网ps基础课程 拥有自己的虚拟主机 传送...

    shiguibiao 评论0 收藏0
  • PHP程序员学习路线

    摘要:第一阶段基础阶段基础程序员重点把搞熟练核心是安装配置基本操作目标能够完成基本的系统安装,简单配置维护能够做基本的简单系统的开发能够在中型系统中支持某个功能模块的开发。本项不做重点学习,除非对前端有兴趣。 第一阶段:基础阶段(基础PHP程序员) 重点:把LNMP搞熟练(核心是安装配置基本操作) 目标:能够完成基本的LNMP系统安装,简单配置维护;能够做基本的简单系统的PHP开发;能够在P...

    genedna 评论0 收藏0
  • Spring Boot 2.x 系列教程:WebFlux 系列教程大纲(一)

    摘要:使用则需要及以上版本。开发使用框架七系列教程目录系列教程大纲快速入门实践实践整合整合中和实践整合中实现缓存中实现通信集成测试及部署实战图书管理系统 WebFlux 系列教程大纲 一、背景 大家都知道,Spring Framework 是 Java/Spring 应用程序跨平台开发框架,也是 Java EE(Java Enterprise Edition) 轻量级框架,其 Spring ...

    jone5679 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<