MongoDB

来自百合仙子's Wiki
跳转到导航 跳转到搜索

NoSQL 数据库,使用 bson 格式(二进制的 json)存储,C/S 架构。其客户端 mongo 使用 Javascript 语法。

数据库操作

以下皆以其的 Javascript shell 为例。

查询

[1]

最简单的查询

db.test.find({name: 'test'})

常用运算符

//比较
db.test.find({value: { $gt: 0 }})

//存在性
db.test.find({phone: {$exists: true}}) //true 不能换成 1

MongoDB 使用的是 PCRE

db.test.find({name: /y/i})
db.test.find({name: {'$regex': "y"}})
db.customers.find({name: {$regex : 'acme.*corp', $options: 'i'}})

使用表达式/函数查询

db.test.find("this.name.indexOf('y') >= 0")
db.test.find({$where: function() { return this.name.indexOf('y') >= 0 }})
db.test.find(function() { return this.name.indexOf('y') >= 0 })

数组

当值为数组而查询条件不是时,只要数组中有一个匹配查询值即为匹配成功。

指定返回的字段

传递给 find() 第二个参数,指定要返回的字段为真值,或者不要的为假值。 _id 字段会一直都返回。

db.test.find({phone: {$exists: true}}, {name: 1})

更新

db.collection.update(criteria, objNew, upsert, multi)

指定第三个参数为 true ,则 documents 不存在时插入。要更新匹配的所有 documents,指定第四个参数为 true[2]

db.test.update(condition, {$set: {name: value}})
{$addToSet: {field: value}}
//To add many values
{$addToSet: {a: {$each: [3 , 5 , 6]}}}

更改字段名,使用 $rename 操作[3]

db.test.update({}, {$rename: {old: 'new'}}, false, true)

$each

在版本 2.4 之前, $each 操作符[4]仅在 $addToSet 中被支持。2.4 开始支持在 $push 中被支持。前者不保证插入的顺序,而后者会保证。

删除

db.test.remove(condition)

索引

建立索引[5]

db.things.ensureIndex({firstname: 1})

建立索引时,指定 1 为升序, -1 为降序。

要建立不重复索引,在第二个参数中指定 unique: true。如果有重复项会失败,除非同时指定 dropDups: true 来删除重复项。[6]

命令

在 mongo shell 中,使用 db.runCommand 来执行一个服务端命令。

getLastError [7]
最后操作的状态

其它

重命名

MongoDB(2.4.5)不支持重命名数据库[8][9]。重命名数据库文件不可行,因为文件中包含数据库名的元信息,会在 repair 操作后丢失全部数据。要重命名一个数据库,只能先复制再删除(会重建索引)。

数据类型

时间

MongoDB 使用 JavaScript 中的 Date 或者自己的 ISODate 类型表示时间,精度为毫秒[10]Pythondatetime (精度为微秒)在向其转换时会有精度损失。

MongoDB 的所存储的时间为 UTC 时间。使用 Python 的 naive datetime 类型时,需要转成 UTC 时间。

地理位置

点临近查询示例(适用于 MongoDB 2.4 以上版本)。其中, $maxDistance 的单位是(2.4.3 版本验证)。

>>> db.test.save({'loc': {'type': 'Point', 'coordinates': [114, 88]}})
ObjectId('51ad5b7a0580701a25bb4406')
>>> db.test.save({'loc': {'type': 'Point', 'coordinates': [114, 20]}})
ObjectId('51ad5b7a0580701a25bb4407')
# 建立需要的索引
>>> db.test.ensure_index([('loc', pymongo.GEOSPHERE)])
'loc_2dsphere'
# 这两点的距离为 313.9km
>>> db.test.find({'loc': {'$near': {'type': 'Point', 'coordinates': [117, 20]}, '$maxDistance': 350000}})
[{'_id': ObjectId('51ad5b7a0580701a25bb4407'),
  'loc': {'coordinates': [114, 20], 'type': 'Point'}}]
>>> db.test.find({'loc': {'$near': {'type': 'Point', 'coordinates': [117, 20]}, '$maxDistance': 300000}})
[]
# 这两点的距离为 243.3km
>>> db.test.find({'loc': {'$near': {'type': 'Point', 'coordinates': [180, 88]}, '$maxDistance': 300000}})
[{'_id': ObjectId('51ad5b7a0580701a25bb4406'),
  'loc': {'coordinates': [114, 88], 'type': 'Point'}}]

Replication

Replica Set

默认每个节点的 priority 为 1,可修改。

默认每个节点的 votes 为 1,只有获得大多数票时一个节点才可以成为 primary。修改此选项将可以在三节点的 ReplSet 中实现单一节点也可成为 primary。不建议修改。[11]

shell 中的命令:

rs.help()
帮助
rs.initiate(config)
初始化 ReplSet
rs.conf()
获取配置
rs.reconfig(config)
更新配置
rs.status()
ReplSet 的状态

master/slave

本地启动一个 master/slave 实例(启动顺序无关)[12]

mongod --master --port 27018 --dbpath data/a --fork --logpath a.log
mongod --slave --source localhost:27018 --port 27019 --dbpath data/b --fork --logpath b.log

slave 的数据将和 master 的同步,但是在 slave 本地的更改(如单独运行过)不会同步到 master(也不会消失)。

如果使用了授权,在双方的 local 数据库中添加 repl 用户即可。[13]

要将 slave 切换为 master:[14]

  1. 停止双方数据库进程
  2. 备份或者删除 slave 的 local.* 文件
  3. 使用 master 模式启动原 slave

shell

shell 内建有 tojsonprintjson 两个函数。 find() 的返回值具有方法 forEach [15]

db.person.find().forEach(printjson)

注意

32 位系统

  • 数据+索引+日志最大为 2GB
  • 默认日志关闭

备份

  • MongoDB 的数据库可在运行时复制后给其它 MongoDB 实例使用,但是需要先使用 --repair 命令修复。

内存使用

如果单台机器上部署多个 mongod,或者可用内存少于可见内存(如 lxc 等限制内存使用时),需要手动配置 storage.wiredTiger.engineConfig.cacheSizeGB 设置。[16]

据称在 OpenVZ 上,由于 OpenVZ 报告的是瞬间可用内存,导致 MongoDB 使用过多内存。

外部链接

Web 界面

服务提供者

改进

参考资料