浅尝辄止MongoDB:基础

目录

一、简介

1. 基本概念

2. 存储格式

二、安装

1. 选择版本

2. 安装

三、数据模型

1. 设计数据库

2. 构建索引

三、使用地理空间索引


        大部分摘自《MongoDB大数据处理权威指南》(第3版)。 

一、简介

        MongoDB(源自单词humongous)是一个只用于处理文档的数据库。不同于关系数据库管理系统(Relational Database Management System,RDBMS),它没有表、模式、SQL或行的概念,也没有事务、ACID兼容性、连接、外键等特性。正因如此,相对于关系数据库来说,MongoDB最大的特点就是简单、快速、易扩展。(虽然MongoDB不支持事务,但在同时使用至少两台服务器时可以提供持久性,这也是生产环境部署时推荐使用的基本配置。主服务器可以在复制服务器确认接收到数据后,再确认数据已被接收,也就是一种全同步复制思想的实现。)

1. 基本概念

(1)数据库
        MongoDB中数据库与和关系数据库系统中的概念类似。关系数据库系统中的一个数据库是表的集合,而MongoDB数据库可以看作是集合的集合。数据库可以按需创建,比较自然的做法是为每个用户创建一个数据库。

(2)集合
        MongoDB中的集合有点类似于关系数据库中的表,但它更灵活,因为是无模式的,集合中的每个文档不要求有同样的结构。在RDBMS中,表是严格定义的,只能将预定于好的数据行放入表中。在MongoDB中,集合就是一组元素的集合,其中的元素不必相似。允许在一个集合中混合各种不同的元素。
        在第一次保存文档时,MongoDB可以自动创建所引用的集合,这意味着可以按照需求即时创建集合,但并不建议这样做。最好还是跟操作表一样,先创建集合,再在其中创建文档。

(3)文档
        一个文档代表了MongoDB中的一个存储单元。在RDBMS中,存储单元被称为行,行是固定格式的,而MongoDB中的文档可以由任意数目的键值组成。键是一个标签,大致相当于RDBMS中的列名,可以使用键引用文档中的数据。
        在关系数据库中,必须能够通过某种方式唯一定位一条指定的记录,否则将无法引用特定的行。为此,通常需要添加一个字段用于存储称一个唯一值(称为主键),或者一组能够唯一定位指定行的字段(称为复合主键)。
        出于相同的原因,MongoDB要求每个文档必须有唯一标识符:在MongoDB中,该标识符被称为_id。除非该字段指定某个值,否则MongoDB将自动创建该唯一值。现在人们更愿意使用MongoDB创建的默认ID值,如果不确定键的唯一性或者不希望担心这件事情,那么最好还是使用MongoDB提供的默认键。

(4)键/值
        文档由键和值组成,键和值总是成对出现。与RDBMS不同,RDBMS中的所有字段必须有值,即使值是NULL,而MongoDB不要求文档必须含有特定的值。如果MongoDB中不含某个键/值对,那它就被认为是不存在的。

2. 存储格式

        MongoDB使用一种称为BSON(二进制JSON的英文简称)的格式存储数据,因此是无模式的。BSON通过使计算机更容易处理和搜索文档的方式,使MongoDB处理速度变得更快。BSON还添加了一些标准JSON不支持的特性,包括存储二进制数据,以及处理特定数据类型。BSON可以存储任何JSON文档,但有效的BSON文档可能不是有效的JSON。每种语言都有自己的驱动,可完成数据和BSON之间的转换,而不需要使用JSON作为中间语言。MongoDB中的BSON数据是自包含的,尽管相似的数据文档被存储在一起,但各个文档之间并没有关系。这意味着所需要的一个文档在同一个地方。因为MongoDB查询将在文档中寻找特定的键和值,该信息可以轻松扩展到所有的可用服务器上。每台服务器都将检查该查询,并返回结果。这样,可扩展性与性能的提升几乎是线性的。

二、安装

1. 选择版本

        MongoDB以C++编写,官网提供了Linux、Mac OS、Windows和Solaris的二进制包。32位版本的MongoDB数据库大小被限制为小于等于2GB,因为MongoDB内部使用内存映射文件来实现高性能。64位版本的MongoDB不含任何限制,所以在生产环境中应该优先使用64位版本。

        另外需要关注MongoDB软件自己的版本:正式版、旧版和开发板。正式版表示它是最近可用的稳定版本。当新的版本发布之后,之前的稳定版就成了旧版。开发版通常被认为是不稳定版本,该版本仍在开发中,其中包含许多修改,将其发布主要用于公测。

        MongoDB使用的版本号方式为:奇数版本号代表开发版。如果版本号的第二个号码是偶数,它就是稳定版,否则是开发版。版本号包含三部分数字:

  • 第一个数字代表主版本,只有在完整版本升级时才会改变。
  • 第二个数字代表发布版,表示版本是开发版还是稳定版。
  • 第三个数字代表修订号,用于解决缺陷和安全问题。

2. 安装

        下面安装从MongoDB官网下载的4.0.2版本。
(1)建立mongodb用户

useradd mongodb

        基于通用的安全原因,不用root启动应用程序。后面步骤用mongodb用户执行。

(2)解压

tar zxvf mongodb-linux-x86_64-rhel70-4.0.2.tgz
mv mongodb-linux-x86_64-rhel70-4.0.2 mongodb-4.0.2
mkdir /home/mongodb/mongodb-4.0.2/data/

(3)将执行文件路径加入资源文件
        在~/.bash_profile的PATH中加入:

PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/mongodb/mongodb-4.0.2/bin

        使得配置生效:

source ~/.bash_profile

(3)建立配置文件/home/mongodb/mongodb-4.0.2/mongodb.conf,内容如下。

logpath    = /home/mongodb/mongodb-4.0.2/data/mongodb.log
pidfilepath = /home/mongodb/mongodb-4.0.2/data/mongodb.pid
dbpath = /home/mongodb/mongodb-4.0.2/data/

(4)启动

mongod -f /home/mongodb/mongodb-4.0.2/mongodb.conf &

(5)登录

[mongodb@hdp4~]$mongo
MongoDB shell version v4.0.2
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 4.0.2
Server has startup warnings: 
2018-09-20T15:36:12.362+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] ** WARNING: This server is bound to localhost.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          Remote systems will be unable to connect to this server. 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          Start the server with --bind_ip <address> to specify which IP 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          addresses it should serve responses from, or with --bind_ip_all to
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          bind to all interfaces. If this behavior is desired, start the
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **          server with --bind_ip 127.0.0.1 to disable this warning.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 10240 processes, 512000 files. Number of processes should be at least 256000 : 0.5 times number of files.
2018-09-20T15:36:12.363+0800 I CONTROL  [initandlisten] 
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).

The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---

>

        可以看到,用mongo登录后显示5个警告信息,下面依次加以说明并解决。
        第一个警告指出缺省MongoDB没有加访问控制,解决方法是添加用户,并配置auth选项。

> use admin;
switched to db admin
> db.createUser(
... {
...   user: "wxy",
...   pwd: "123456",
...   roles: [ { role: "__system", db: "admin" } ]
... }
... )
Successfully added user: {
    "user" : "wxy",
    "roles" : [
        {
            "role" : "__system",
            "db" : "admin"
        }
    ]
}
> 

        在/home/mongodb/mongodb-4.0.2/mongodb.conf中添加:

auth = true

        重启MongoDB:

> use admin
switched to db admin
> db.shutdownServer()
server should be down...
2018-09-20T16:02:10.479+0800 I NETWORK  [js] trying reconnect to 127.0.0.1:27017 failed
2018-09-20T16:02:10.479+0800 I NETWORK  [js] reconnect 127.0.0.1:27017 failed failed 
> exit
bye
2018-09-20T16:02:23.409+0800 I NETWORK  [js] trying reconnect to 127.0.0.1:27017 failed
2018-09-20T16:02:23.409+0800 I NETWORK  [js] reconnect 127.0.0.1:27017 failed failed 
2018-09-20T16:02:23.410+0800 I QUERY    [js] Failed to end session { id: UUID("d5cd31bd-f064-4e23-bb4b-1f2a47e1fc72") } due to SocketException: socket exception [CONNECT_ERROR] server [couldn't connect to server 127.0.0.1:27017, connection attempt failed: SocketException: Error connecting to 127.0.0.1:27017 :: caused by :: Connection refused]
[1]+  Done                    mongod -f /home/mongodb/mongodb-4.0.2/mongodb.conf  (wd: ~)
(wd now: ~/mongodb-4.0.2)
[mongodb@hdp4~/mongodb-4.0.2]$mongod -f /home/mongodb/mongodb-4.0.2/mongodb.conf &

        再次登录,第一个警告消失:

mongo -u "wxy" -p "rockey" --authenticationDatabase "admin"

        第二个警告是说缺省只允许本机连接MongoDB服务器。解决方法是设置bind选项。如在配置文件中添加如下一行,允许所有主机连接:

bind_ip_all = true

        重启MongoDB后再次登录,第二个警告消失。

        第三、四个警告是建议将transparent_hugepage的两个参数设置为never,用root用户执行下面的命令:

echo never >>  /sys/kernel/mm/transparent_hugepage/enabled
echo never >>  /sys/kernel/mm/transparent_hugepage/defrag

        重启MongoDB后再次登录,这两个警告消失。

        最后一个警告是说soft rlimits值太小,建议设置为256000,用root用户执行下面的操作。在/etc/security/limits.conf文件中添加如下两行:

mongodb soft nproc 256000 
mongodb hard nproc 256000

在/etc/profile文件中添加下面一行:

ulimit -u 256000

重启MongoDB,重新登录,所有警告都没有了。

三、数据模型

        MongoDB被称为无模式数据库,但并不意味着MongoDB的数据结构是完全没有模式的。例如,在MongoDB中也需要定义集合和索引。然而不需要为新增加的文档预定义任何结构,这与使用关系数据库时是不同的。简单说MongoDB是一个极其动态的数据库。

1. 设计数据库

(1)集合
        可以将集合看作存储文档的容器。MongoDB中有几种不同类型的集合。默认的集合按照大小进行扩展,添加的数据越多,集合就变得越大。还可以定义固定大小(capped)的集合,只可包含特定数量的数据,最老的文档将被新增加的文档代替。

        MongoDB中的一个数据库中的集合都有唯一的名字,不同数据库中的集合允许重名。通常建议使用9个字符以内的简短名称,MongoDB支持的集合名称的最大长度为128。注意MongoDB中的对象名称、命令、函数等都区分大小写。

        运行MMAPv1存储引擎的单个数据库默认最多可以创建24000个名称空间,WiredTiger存储引擎没有这个限制。每个集合至少包含两个名称空间:一个用于集合自身,另一个用于集合中创建的第一个索引。如果为每个集合添加更多索引,将使用更多名称空间。这意味着从理论上讲,如果每个集合都只含有一个索引,那么每个数据库最多可以拥有12000个集合。不过在执行MongoDB服务应用(mongod)时,可以通过提供nssize参数,把名称空间的数目至多增加到2047MB。

(2)文档

        文档由键值对组成,键的类型为字符串,但可以使用许多不同类型的数据作为值。下面是所有可以添加到文档中的数据类型:

  • String:字符串类型,常用于存储文本值,区分大小写。
  • Integer(32位或64位):整数类型,常用于存储数值。
  • Boolean:该数据类型的值要么为真,要么为假。
  • Double:用于存储浮点数。
  • Min/Max keys:分别用于与BSON中的最低和最高值作比较。
  • Arrays:用于存储数组。
  • Timestamp:存储时间戳,可以方便记录文档修改或添加的时间。
  • Object:用于存储嵌入文档。
  • Null:用于存储null值。
  • Symbol:该数据类型的用法与字符串一致,但通常将被语言保留用于特定的符号类型。
  • Date *:用于存储UNIX时间格式的当前日期或时间(POSIX时间)。
  • Object ID *:用于存储文档的ID。
  • Binary data *:用于存储二进制数据。
  • Regular expression *:该数据类型用于正则表达式,所有选项都通过按字母顺序提供的特殊字符表示。
  • JavaScript Code *:用于JavaScript代码。

        最后5种带有星号的数据类型都不是JSON类型,它们是BSON中使用的特殊数据类型。

(3)在文档中内嵌或引用信息
        可以选择在文档中内嵌信息,或者引用另一个文档中的信息。内嵌信息意味着在文档自身中添加某种类型的数据,引用信息意味着创建对另一个包含了特定数据的文档的应用。通常,使用关系数据库时会采取引用信息的方式,如范式设计,目的是消除数据冗余,保证数据一致性。

        不过在MongoDB中,内嵌信息会更加简单,毕竟,文档天生能够实现这样的操作。采用这种方式将保持数据库简洁,保证所有相关的信息都存储在单个文档中,甚至因为数据在磁盘中存储位置相近,处理速度会更快。

        例如在数据库中存储CD数据,关系数据库中的数据结构如下:

|_media
    |_cds
        |_id, artist, title, genre, releasedate
    |_ cd_tracklists
        |_cd_id, songtitle, length

        在非关系数据库中,数据结构如下:

|_media
    |_items
        |_<document>

        其中文档结构如下:

{
    "Type": "CD",
    "Artist": "Nirvana",
    "Title": "Nevermind",
    "Genre": "Grunge",
    "Releasedate": "1991.09.24",
    "Tracklist": [
        {
        "Track" : "1",
        "Title" : "Smells Like Teen Spirit",
        "Length" : "5:02"
        },
        {
        "Track" : "2",
        "Title" : "In Bloom",
        "Length" : "4:15"
        }
    ]
}

        关系数据库中至少需要两个表,而在非关系数据库中,只要一个集合和一个文档,曲目列表信息将内嵌在文档中。当获取指定CD的信息时,只需要将当个文档的信息加载到内存中即可。MongoDB中的经验法则是,尽可能使用内嵌数据,这种方式高效且总是可行的。其本质就是用数据冗余替代表关联,MongoDB中所有的引用都将在数据库中产生另一个查询。

2. 构建索引

        MongoDB中的索引是一种数据结构,用于收集集合中文档特定字段的值的信息。MongoDB的查询优化器使用该数据结构对集合中的文档进行快速排序。这和关系数据库的索引作用是一致的。

        索引保证了在文档中查询数据的速度。基本上可以将索引看作已经执行并存储了结果的预定义查询。MongoDB中通用的经验规则是:对于需要在MySQL中创建索引的场景,在MongoDB中也应该创建索引。创建索引的最大优点在于查询常用信息时会很快,因为这些查询不需要遍历整个数据库以收集该信息。

        每个集合最多可以拥有40个索引。添加索引将提高查询速度,但也会降低插入或删除的速度。最好在读操作多于写操作的集合中添加索引。当写操作多于读操作时,索引可能降低性能。

        所有索引信息都存储在数据库的system.indexes集合中。可以运行db.indexes.find()命令来查看目前已经存储的索引。为了查看某个集合中创建的索引,可以使用命令db.collection.getIndexes()。

三、使用地理空间索引

        MongoDB从版本1.4开始就已经实现了对地理空间索引的支持,可用于处理基于位置的查询。要添加地理空间信息的文档必须含有一个子对象或数组(第一个元素指定对象类型,紧接着是该元素的经纬度),例如:

> db.restaurants.insert({name:"Kimono",loc:{type:"Point",coordinates:[52.370451,5.217497]}});
WriteResult({ "nInserted" : 1 })
>

        参数type可用于指定文档的对象类型,可以是Point、LineString或Polygon。Point类型用于指定某个条目所在的准确位置,因此需要两个值:经度和维度。类型LineString可用于指定某个沿着特定路线扩展的条目(例如街道),因此需要起点和终点:

> db.streets.insert( {name: "Westblaak", loc: { type: "LineString", coordinates: [ [52.36881,4.890286],[52.368762,4.890021] ] } } );
WriteResult({ "nInserted" : 1 })
>

        Polygon类型可用于指定图形。指定该类型时,需要保证起点和终点是一致的,从而可以闭合这个环。另外,该点的坐标将通过在数组中内嵌数组的方式提供:

> db.stores.insert( {name: "SuperMall", loc: { type: "Polygon", coordinates: [ [ [52.146917,5.374337], [52.146966,5.375471], [52.146722,5.375085], [52.146744,5.37437], [52.146917,5.374337] ] ] } } );
WriteResult({ "nInserted" : 1 })
>

        所有Multi版本()是选中数据类型的数组,如下面的MultiPoint:

> db.restaurants.insert({name: "Shabu Shabu", loc: { type: "MultiPoint", coordinates: [[52.1487441, 5.3873406], [52.3569665,4.890517]] }});
WriteResult({ "nInserted" : 1 })
>

        在大多数情况下,Point类型是适用的。

        一旦在文档中添加地理空间信息,就可以创建此种类型的索引(当然也可以提前创建索引),为ensureIndex()函数提供2dsphere参数:

> db.restaurants.ensureIndex( { loc: "2dsphere" } );
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}
>

        ensureIndex()函数用于添加自定义索引。参数2dsphere将告诉ensureIndex(),它在索引坐标或类地球球体上的其它形式的二维信息。默认情况下,ensureIndex()将假设提供的是经度和维度,并认为它们的范围是-180到180,但可以使用min和max参数改写这些信息:

> db.restaurants.ensureIndex( { loc: "2dsphere" }, { min : -500 , max : 500 } );
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}
>

        还可以通过使用辅助键值(也称为复合索引)扩展地理空间索引。如果希望查询多个值,例如位置(地理空间信息)或分类(升序),那么该结构是非常有用的;

> db.restaurants.ensureIndex( { loc: "2dsphere", category: 1 } );
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 3,
    "ok" : 1
}
>

        查询地理空间信息。

# 选择数据库

> use restaurants;
switched to db restaurants

# 查看集合为空

> show collections;

# 插入数据

> db.restaurants.insert( { name: "Kimono", loc: { type: "Point", coordinates: [ 52.370451, 5.217497] } } );
WriteResult({ "nInserted" : 1 })
> db.restaurants.insert( {name: "Shabu Shabu", loc: { type: "Point", coordinates: [51.915288,4.472786] } } );
WriteResult({ "nInserted" : 1 })
> db.restaurants.insert( {name: "Tokyo Cafe", loc: { type: "Point", coordinates: [52.368736, 4.890530] } } );
WriteResult({ "nInserted" : 1 })

# 查看集合,自动建立restaurants

> show collections;
restaurants

# 在loc上创建地理空间索引

> db.restaurants.ensureIndex ( { loc: "2dsphere" } );
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}

# 精确搜索,结果为空

> db.restaurants.find( { loc : [52,5] } );
> 

        前面的搜索未返回结果,因为该查询太具体了。本例中更好的方式应该是搜索某个包含接近指定值的信息的文档。可以使用$near操作符实现该操作。注意这种方式要求type操作符:

> db.restaurants.find( { loc : { $near : { $geometry : { type : "Point",
... coordinates: [52.338433,5.513629] } } } } );
{ "_id" : ObjectId("5ba9d49ff272e645164d5776"), "name" : "Kimono", "loc" : { "type" : "Point", "coordinates" : [ 52.370451, 5.217497 ] } }
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
{ "_id" : ObjectId("5ba9d4a5f272e645164d5777"), "name" : "Shabu Shabu", "loc" : { "type" : "Point", "coordinates" : [ 51.915288, 4.472786 ] } }
> 

        尽管该结果看着好多了,但仍然存在着一个问题:所有的文档都被返回了。在不使用任何其它操作符的情况下,$near将返回头100条记录,并按照它们与指定坐标的距离进行排序。可以限制返回结果,例如使用limit函数返回开始的两条记录:

> db.restaurants.find( { loc : { $near : { $geometry : { type : "Point", coordinates: [52.338433,5.513629] } } } } ).limit(2);
{ "_id" : ObjectId("5ba9d49ff272e645164d5776"), "name" : "Kimono", "loc" : { "type" : "Point", "coordinates" : [ 52.370451, 5.217497 ] } }
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
> 

        或者只返回指定范围内的结果,这可以通过添加$maxDistance或$minDistance操作符实现。使用其中一个操作符将告诉MongoDB只返回在从指定点开始的最大或最小距离(按米计算)之内的结果:

> db.restaurants.find( { loc : { $near : { $geometry : { type : "Point",
... coordinates: [52.338433,5.513629] }, $maxDistance : 40000 } } } );
{ "_id" : ObjectId("5ba9d49ff272e645164d5776"), "name" : "Kimono", "loc" : { "type" : "Point", "coordinates" : [ 52.370451, 5.217497 ] } }
> 

        可以看出,该查询只返回了一个结果:从起点开始40公里范围内的一家餐馆。注意返回结果的数目与执行查询所需的时间存在直接关系。

        除了$near操作符之外,MongoDB还有$geoWithin操作符。可以使用该操作符寻找特定图形中的所有记录。这时候就可以查找位于$box、$polygon、$center和$centerSphere图形中的记录,$box代表矩形,$polygon代表选择的特殊图形,$center代表圆形,$centerSphere定义球体上的圆形。下面通过一些例子来演示它们的用法。注意在MongoDB 2.4中,$within操作符被弃用,取而代之的是$geoWithin。该操作符并不严格要求使用地理空间索引。另外,与$near操作符不同,$geoWithin将返回未排序的结果,这提高了查询的性能。

        为了使用$box图形,首先需要指定矩形的左下角和右上角坐标:

> db.restaurants.find( { loc: { $geoWithin : { $box : [ [52.368549,4.890238],
... [52.368849,4.89094] ] } } } );
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
> 

        类似地,为了查找特定图形中的记录,需要指定一组包含了点坐标信息的嵌套数组。另外,注意第一个和最后一个坐标必须是一致的,用于正确地闭合图形所形成的环:

> db.restaurants.find( { loc :
...  { $geoWithin :
...     { $geometry :
...        { type : "Polygon" ,
...          coordinates : [ [
...             [52.368739,4.890203], [52.368872,4.890477], [52.368726,4.890793],
...             [52.368608,4.89049], [52.368739,4.890203]
...           ] ]
...        }
...      }
...  } });
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
>

        查找基本$circle图形中记录的代码非常简单。在这种情况下,只需要在执行find()函数之前指定圆的中心和半径(使用坐标系统使用的单位)即可:

> db.restaurants.find( { loc: { $geoWithin : { $center : [ [52.370524, 5.217682], 10] } } } );
{ "_id" : ObjectId("5ba9d49ff272e645164d5776"), "name" : "Kimono", "loc" : { "type" : "Point", "coordinates" : [ 52.370451, 5.217497 ] } }
{ "_id" : ObjectId("5ba9d4a5f272e645164d5777"), "name" : "Shabu Shabu", "loc" : { "type" : "Point", "coordinates" : [ 51.915288, 4.472786 ] } }
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
>

        注意,从MongoDB 2.2.3开始,$center操作符可以与非地理空间索引一起使用。不过,还是推荐创建地理空间索引,这样可以提高性能。为了查找球体上某个圆形之内的记录,可以使用$centerSphere操作符,该操作符类似于$center:

> db.restaurants.find( { loc: { $geoWithin : { $centerSphere : [ [52.370524, 5.217682], 10]
... } } } );
{ "_id" : ObjectId("5ba9d49ff272e645164d5776"), "name" : "Kimono", "loc" : { "type" : "Point", "coordinates" : [ 52.370451, 5.217497 ] } }
{ "_id" : ObjectId("5ba9d4a5f272e645164d5777"), "name" : "Shabu Shabu", "loc" : { "type" : "Point", "coordinates" : [ 51.915288, 4.472786 ] } }
{ "_id" : ObjectId("5ba9d4adf272e645164d5778"), "name" : "Tokyo Cafe", "loc" : { "type" : "Point", "coordinates" : [ 52.368736, 4.89053 ] } }
>

        MongoDB还提供了geoNear()函数,它的工作方式与find()一样,不过它还在结果中提供了从指定点到每个记录的距离。函数geoNear()中还包含一些额外的诊断信息:

> db.runCommand( { geoNear : "restaurants", near : { type : "Point", coordinates:
... [52.338433,5.513629] }, spherical : true});
{
    "results" : [
        {
            "dis" : 33155.51908653251,
            "obj" : {
                "_id" : ObjectId("5ba9d49ff272e645164d5776"),
                "name" : "Kimono",
                "loc" : {
                    "type" : "Point",
                    "coordinates" : [
                        52.370451,
                        5.217497
                    ]
                }
            }
        },
        {
            "dis" : 69443.96447626318,
            "obj" : {
                "_id" : ObjectId("5ba9d4adf272e645164d5778"),
                "name" : "Tokyo Cafe",
                "loc" : {
                    "type" : "Point",
                    "coordinates" : [
                        52.368736,
                        4.89053
                    ]
                }
            }
        },
        {
            "dis" : 125006.87091822099,
            "obj" : {
                "_id" : ObjectId("5ba9d4a5f272e645164d5777"),
                "name" : "Shabu Shabu",
                "loc" : {
                    "type" : "Point",
                    "coordinates" : [
                        51.915288,
                        4.472786
                    ]
                }
            }
        }
    ],
    "stats" : {
        "nscanned" : 10,
        "objectsLoaded" : 3,
        "avgDistance" : 75868.78482700557,
        "maxDistance" : 125006.87091822099,
        "time" : 3450
    },
    "ok" : 1
}
>

 

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值