MongoDB数据模型(二)

原文地址

接上一篇

四、模型树结构

父引用的模型树结构

这个数据模型描述了一个树形结构,在子节点中存储父节点的引用。

模式

父引用模式存储每个树节点到文档中,除了树节点外,文档还存储了父节点的id。

考虑以下目录的层级关系。

以下为应用实例

db.categories.insert( { _id: "MongoDB", parent: "Databases" } )
db.categories.insert( { _id: "dbm", parent: "Databases" } )
db.categories.insert( { _id: "Databases", parent: "Programming" } )
db.categories.insert( { _id: "Languages", parent: "Programming" } )
db.categories.insert( { _id: "Programming", parent: "Books" } )
db.categories.insert( { _id: "Books", parent: null } )

查询一个节点的父节点变得快速且直观

db.categories.findOne( { _id: "MongoDB" } ).parent

还可以对parent字段创建索引以提高查询速度

db.categories.createIndex( { parent: 1 } )

通过parent字段查询其直接子节点

db.categories.find( { parent: "Databases" } )

这种父引用模式是实现树存储的简单方法,缺点是获取子树时则需要多个查询。

子引用的模型树结构

这个数据模型描述了树形结构,存储子节点的引用到父节点中。

模式

子引用模式存储每个树节点到一个文档中,除了树节点,文档还存储了包含其子节点id的数组。

考虑与上一个图中相同的目录层级关系,其子引用模式的实现如下

db.categories.insert( { _id: "MongoDB", children: [] } )
db.categories.insert( { _id: "dbm", children: [] } )
db.categories.insert( { _id: "Databases", children: [ "MongoDB", "dbm" ] } )
db.categories.insert( { _id: "Languages", children: [] } )
db.categories.insert( { _id: "Programming", children: [ "Databases", "Languages" ] } )
db.categories.insert( { _id: "Books", children: [ "Programming" ] } )

查询获取一个节点的直接子节点则变得快速且直观

db.categories.findOne( { _id: "Databases" } ).children

创建children字段上的索引以实现快速查询

db.categories.createIndex( { children: 1 } )

通过children信息查询其父节点以及兄弟节点信息

db.categories.find( { children: "MongoDB" } )

子引用模式提供了一种树存储的合适方案,只要不需要对子树操作就行(单个查询无法保证获取一个节点的所有子节点)。对于存储图像,其中一个节点可能有多个父节点,那这个模式也是很好的方案。

祖先数组的模型树结构

这个数据模型描述了树形结构,使用对父节点的引用和一个数组来存储所有的祖先节点。

模式

文档中除了存储每个树节点,还存储了一个数组,其他暴露了所有祖先节点的id或者路径(祖先节点的id按顺序排序组成路径)。

考虑跟上面图中相同的目录层级关系

以下实际实例中,文档除了ancestors字段,还有parent字段,parent字段存储了直接父节点的引用。

db.categories.insert( { _id: "MongoDB", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } )
db.categories.insert( { _id: "dbm", ancestors: [ "Books", "Programming", "Databases" ], parent: "Databases" } )
db.categories.insert( { _id: "Databases", ancestors: [ "Books", "Programming" ], parent: "Programming" } )
db.categories.insert( { _id: "Languages", ancestors: [ "Books", "Programming" ], parent: "Programming" } )
db.categories.insert( { _id: "Programming", ancestors: [ "Books" ], parent: "Books" } )
db.categories.insert( { _id: "Books", ancestors: [ ], parent: null } )

查询获取一个节点的祖先节点或者路径则变得快速而直观

db.categories.findOne( { _id: "MongoDB" } ).ancestors

对ancestors字段创建索引提高查询速度

db.categories.createIndex( { ancestors: 1 } )

查询ancestors字段以查找它的所有后代节点

db.categories.find( { ancestors: "Programming" } )

祖先数组模式提供了查询某节点的后代节点以及某节点的祖先节点的有效方案,所以当需要对子树节点进行操作时,这个模式是一个很好的选择。

祖先数组模式比具体化路径(Materialized Paths)模式稍慢,但是使用更直观。

具体化路径(Materialized Paths)的模型树结构

这个数据模型描述了树形结构,存储文档间的全关系路径。

模式

具体化路径中,文档除了存储树节点之外,还存储了节点的祖先的id或者路径。尽管具体化路径模式要求额外的步骤处理字符串和正则表达式,这个模式也提供了处理路径的灵活性,如通过部分路径查找节点。

考虑与上面的图中相同的目录层级关系

具体化路径模式中,存储路径到path字段中,路径使用逗号作为分隔符

db.categories.insert( { _id: "Books", path: null } )
db.categories.insert( { _id: "Programming", path: ",Books," } )
db.categories.insert( { _id: "Databases", path: ",Books,Programming," } )
db.categories.insert( { _id: "Languages", path: ",Books,Programming," } )
db.categories.insert( { _id: "MongoDB", path: ",Books,Programming,Databases," } )
db.categories.insert( { _id: "dbm", path: ",Books,Programming,Databases," } )

通过path字段查询所有的节点

db.categories.find().sort( { path: 1 } )  // 按path的升序

对path字段使用正则表达式查找Programming的后代

db.categories.find( { path: /,Programming,/ } ) // 路径包含",Programming,"

查找Books的后代,因为Books是最高节点,故正则表达式以",Books,"开头

db.categories.find( { path: /^,Books,/ } )

对path字段创建索引

db.categories.createIndex( { path: 1 } )

根据具体查询,这个索引可能会提高性能:

  • 对于根节点Books的子树上的查询(例如,/^,Books,/ 或者 /^,Books,Programming,/),path字段的索引会明显提高查询性能。
  • 对于未提供到根节点的路径的子树上的查询(例如, /,Databases,/),或者类似的子树查询,节点在加索引的字符串的中间,这时查询必须扫描所有索引。对这些查询来说,如果索引比整个集合小很多,则索引会提高查询性能。

内嵌集(Nested Sets)的模型树结构

这个数据模型描述了树形结构,优化了查找子树的性能,但是也会导致树的易变性的增加。

模式

内嵌集模式对树作一个往返遍历并标示树中每个节点为停留点。应用程序对每个节点访问两次,第一次为去往遍历,第二次为返回遍历。内嵌集模式中文档除了存储树节点,还存储了其父节点的id,存储其去往停留点到left字段,以及存储返回停留点到right字段。

考虑如下目录的层级关系

下面代码演示了内嵌集的实现

db.categories.insert( { _id: "Books", parent: 0, left: 1, right: 12 } )
db.categories.insert( { _id: "Programming", parent: "Books", left: 2, right: 11 } )
db.categories.insert( { _id: "Languages", parent: "Programming", left: 3, right: 4 } )
db.categories.insert( { _id: "Databases", parent: "Programming", left: 5, right: 10 } )
db.categories.insert( { _id: "MongoDB", parent: "Databases", left: 6, right: 7 } )
db.categories.insert( { _id: "dbm", parent: "Databases", left: 8, right: 9 } )

查询获取一个节点的后代

var databaseCategory = db.categories.findOne( { _id: "Databases" } );
db.categories.find( { left: { $gt: databaseCategory.left }, right: { $lt: databaseCategory.right } } );

内嵌集模式提供了为查找子树的一个快速并有效率的方案,但是在修改树结构时较为麻烦。故这种模式适合不会改变结构的静态树。

五、模型特定的程序上下文

原子操作的模型数据

MongoDB中的写操作,例如db.collection.update(),db.collection.findAndModify(),db.collection.remove()在单个文档级别是原子的。对于那些需要一起被更新的字段,将字段嵌入到文档中可以确保对这些字段的更新是原子的。

例如,考虑这样一种情况,当需要维护书的信息时,包括可以检出的书数量以及当前检出信息,如何确定这两个操作整体的原子性?

可获得的书和检出信息必须同步。这样,将available字段和checkout字段嵌入相同的文档以确保更新文档是原子性的。

{
    _id: 123456789,
    title: "MongoDB: The Definitive Guide",
    author: [ "Kristina Chodorow", "Mike Dirolf" ],
    published_date: ISODate("2010-09-24"),
    pages: 216,
    language: "English",
    publisher_id: "oreilly",
    available: 3,
    checkout: [ { by: "joe", date: ISODate("2012-10-15") } ]
}

那么,根据新的检出信息,可以使用db.collection.update()进行更新,并且对available字段和checkout字段的更新是原子性的。

db.books.update (
   { _id: 123456789, available: { $gt: 0 } },  //查询条件
   {
     $inc: { available: -1 },    //available字段减1
     $push: { checkout: { by: "abc", date: new Date() } }  // checkout字段数组增加一个元素
   }
)

以上操作返回一个WriteResult()对象,包含了操作的有关信息

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

nMatched字段表明1个文档匹配这个更新条件,nModified表明这个操作更新了一个文档。

支持关键字查询的模型数据

关键字搜索与文本搜索或者全文搜索不同,它不提供词干提取或者其他文本处理特性。

此模式描述了支持关键字搜索的方法,以支持程序搜索功能,这个搜索方法使用存储在相同文档中的数组中的关键字,而这个数组作为这个文档的文本字段。与多键索引结合后,这个模式可以支持程序的关键字搜索操作。

模式

为了向文档中增加结构以支持基于关键字的查询,首先向文档中创建一个数组字段,并将关键字以字符串形式添加到数组中。然后可以对这个数组创建多键索引,并创建查询从这个数组中选择数值。

实例:

给定一个图书卷的集合,并想提供一个机遇主题的搜索。对每个卷而言,我们增加topics数组,并尽可能的对这个卷添加关键字到数组中。对Moby-Dick卷可以由如下文档表示,

{ title : "Moby-Dick" ,
  author : "Herman Melville" ,
  published : 1851 ,
  ISBN : 0451526996 ,
  topics : [ "whaling" , "allegory" , "revenge" , "American" ,
    "novel" , "nautical" , "voyage" , "Cape Cod" ]
}

然后对topics数组创建多键索引

db.volumes.createIndex( { topics: 1 } )

多键索引对topics数组中的每个关键字创建索引项。例如,索引中有一个是关于"whaling"的索引项,另一个是关于"allegory"的索引项。

然后基于关键字的查询示例如下

db.volumes.findOne( { topics : "voyage" }, { title: 1 } )

提示:数组中的元素数量很大时,如有几百或上千的关键字,那插入操作会导致加索引花费很大。

关键字索引的限制

使用特定的数据模型和多键索引,MongoDB可以支持关键字搜索。然而,这些关键字索引在以下方面与全文搜索比较则显得不足或者无法相比:

  • 词干提取。关键字查询无法解析关键字为根或者有关词语。
  • 同义。关键字搜索特性必须在应用层提供同义支持或相关查询。
  • 排序。关键字查询不提供判断结果权重的方式。
  • 异步索引。MongoDB同步创建索引,这意味着为关键字使用的索引总是处于当前的并可实时操作。然而,异步创建的索引在某种内容和工作负荷下效率更高。
时间: 2024-10-13 03:08:01

MongoDB数据模型(二)的相关文章

第二课 MongoDB 数据模型

1.课程大纲 本课程主要介绍MongoDB数据模型相关知识.包含文档.集合与数据库的基本概念.用法及命名规则:MongoDB主要的数据类型介绍以及MongoDB Shell的简单介绍与使用. 文档 (Document) 与 集合 MongoDB 数据类型 MongoDB Shell简单介绍与使用 2.课程简单介绍 本课时将解说 MongoDB 数据类型,首先会对 MongoDB 数据类型做一个简单介绍.然后会对当中几个比較重要的同一时候也是我们在实际项目中常常使用到的数据类型做一个具体介绍,这些

MongoDB数据模型和索引学习总结

MongoDB数据模型和索引学习总结 1. MongoDB数据模型: MongoDB数据存储结构: MongoDB针对文档(大文件採用GridFS协议)採用BSON(binary json,採用二进制编码)数据格式来存储和交换数据.Bson吸收了JSON schema-less的特点,存储结构松散,不须要像RDB(关系数据)那样事先定义数据存储的元数据结构.另外添加了多种数据类型的支持和优化,使读写更加高效. (1) BSON 支持的数据类型: Double.String.Object.Arra

MongoDB(二)c客户端

windows下编译mongo-c-driver mongo-c-driver的github地址下载个1.82的release版本后,发现没有vs的什么工程文件,有CMake文件,现在一般都是使用CMake来生成平台的makefile或者工程文件,Zookeeper的c客户端也是CMake形式的.简单来说就是解决了跨平台c编译的问题,官网上的对CMake的介绍: CMake is an open-source, cross-platform family of tools designed to

走进MongoDB(二)

本文从以下四个方面对mongodb进行介绍 一.聚合操作(aggregate operation) 二.文本搜索(text search) 三.数据模型 (DATA MODELS) 四.数据库安全(security) 一.聚合操作 组合多个数据记录,对分组数据记录进行多种操作,最终返回一个单一的结果 实现方式:聚合管道.map-reduce.单用途聚合方法 1.聚合管道 聚合管道是基于数据处理管道模型上的.数据记录经过 多个阶段的管道 最终被转换为聚合结果集. 最基本的过滤管道提供了改变数据集输

MongoDB数据模型(三)

六.数据模型引用 文档 我们已经知道MongoDB以文档的形式存储数据,而文档是JSON风格的数据结构,由一系列的“字段名-值”对组成,如下所示 { "item": "pencil", "qty": 500, "type": "no.2" } 大多用户可访问的数据结构是文档,这些文档可以表示很多含义,包括: 所有数据库记录. 查询选择器,定义选择什么样的记录用以读取.更新和删除操作. 更新定义,定义需要修改

小白来学MongoDB(二)

一.关于windows上使用mongodb mongodb下载地址 官方文档-在windows下安装mongodb 注意:mongodb不支持windows xp系统 在windows上安装mongodb也很简单,点击上面的链接,下载32位或者64位的zip压缩包.或者msi直接安装,在windows上的安装包比较大,110M以上. 下载下来后,解压文件,或者直接运行msi,其中msi直接安装后,默认安装在了C:\Program Files,找到开头是mongodb的,就是了.下面是本人配置的步

MongoDB复制二:复制集的管理

1.修改oplog的大小  需要在每个机器上都配置.先在secondary上操作,最后在primary上操作. 1)以单机的方式重启复制集的实例 db.shutdownServer() 在新的端口中启动实例 mongod --port 37017 --dbpath /usr/local/mongodb-linux-x86_64-3.2.0/data 2)备份原来的oplog [[email protected] mongodb-linux-x86_64-3.2.0]# mongodump --d

MongoDB数据模型

MongoDB中的数据有一个灵活的模式.不像SQL数据库,你必须确定在插入数据之前和声明一个表的模式, MongoDB的集合不执行文档结构.他灵活便利的映射文件一个实体或对象.每个文档可以匹配的数据字段代表的实体, 即使数据有实质性的变化.然而在实践中,集合中的文件共享一个相似的结构.数据建模的关键挑战是平衡应用程序 的需要,数据库引擎的性能特征,数据检索模式.在设计数据模型时,总是考虑应用程序使用的数据(如查询.更新和处 理的数据)以及数据本身固有的结构. 文档结构 MongoDB应用程序的数

MongoDB(二)

MongoDB入门教程(包含安装.常用命令.相关概念.使用技巧.常见操作等) http://www.jb51.net/article/51514.htm 这篇文章主要介绍了MongoDB入门教程,包含安装.常用命令.相关概念.使用技巧.常见操作等,是一篇比较好的入门文章,需要的朋友可以参考下 一.安装和配置   MongoDB 的官方下载站是 http://www.mongodb.org/downloads,可以去上面下载最新的安装程序   Windows 平台的安装   ● 步骤一: 下载 M