MongoDB 教程

mongodb tutorial

安装

https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

主要议程

https://docs.mongodb.com/getting-started/python/

  • Introduction to MongoDB as well as instructions to Import Example Dataset;
  • A brief overview of the Python Driver (PyMongo);
  • Basic Insert, Find, Update, Remove operations plus Aggregation;
  • Instructions on creating Indexes to improve query performance.

数据库驱动

https://docs.mongodb.com/getting-started/python/client/

安装驱动

1
pip install pymongo

使用案例

连接

1
2
3
4
5
6
7
import pymongo
from pymongo import MongoClient
from datetime import datetime
client = MongoClient("mongodb://127.0.0.1:27017")
db = client['test']
coll = db['restaurants']

插入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
result = db.restaurants.insert_one(
{
"address": {
"street": "2 Avenue",
"zipcode": "10075",
"building": "1480",
"coord": [-73.9557413, 40.7720266]
},
"borough": "Manhattan",
"cuisine": "Italian",
"grades": [
{
"date": datetime.strptime("2014-10-01", "%Y-%m-%d"),
"grade": "A",
"score": 11
},
{
"date": datetime.strptime("2014-01-16", "%Y-%m-%d"),
"grade": "B",
"score": 17
}
],
"name": "Vella",
"restaurant_id": "41704620"
}
)
result.inserted_id

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Query
cursor = db.restaurants.find()
# Query by a Top Level Field
cursor = db.restaurants.find({"borough": "Manhattan"})
# Query by a Field in an Embedded Document
cursor = db.restaurants.find({"address.zipcode": "10075"})
# Query by a Field in an Array
cursor = db.restaurants.find({"grades.grade": "B"})
# Specify Conditions with Operators
cursor = db.restaurants.find({"grades.score": {"$gt": 30}})
cursor = db.restaurants.find({"grades.score": {"$lt": 10}})
# Combine Conditions
# Logical AND
cursor = db.restaurants.find({"cuisine": "Italian", "address.zipcode": "10075"})
# Logical OR
cursor = db.restaurants.find(
{"$or": [{"cuisine": "Italian"}, {"address.zipcode": "10075"}]})

排序

1
2
3
4
5
6
7
8
9
10
# Sort
cursor = db.restaurants.find().sort([
("borough", pymongo.ASCENDING),
("address.zipcode", pymongo.ASCENDING)
])
for index,document in enumerate(cursor):
if index > 2:
break
print(document)

修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Update
# Update Top-Level Fields
result = db.restaurants.update_one(
{"name": "Juni"},
{
"$set": {
"cuisine": "American (New)"
},
"$currentDate": {"lastModified": True}
}
)
# Update an Embedded Field
result = db.restaurants.update_one(
{"restaurant_id": "41156888"},
{"$set": {"address.street": "East 31st Street"}}
)
#
result = db.restaurants.update_many(
{"address.zipcode": "10016", "cuisine": "Other"},
{
"$set": {"cuisine": "Category To Be Determined"},
"$currentDate": {"lastModified": True}
}
)
result.matched_count
result.modified_count

删除

1
2
3
4
5
6
7
8
9
10
11
# Delete
# Remove All Documents That Match a Condition
result = db.restaurants.delete_many({"borough": "Manhattan"})
result.deleted_count
# Remove All Documents
result = db.restaurants.delete_many({})
# Drop a Collection
db.restaurants.drop()

聚集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Aggregation
# Group Documents by a Field and Calculate Count
cursor = db.restaurants.aggregate(
[
{"$group": {"_id": "$borough", "count": {"$sum": 1}}}
]
)
for document in cursor:
print(document)
# Filter and Group Documents
cursor = db.restaurants.aggregate(
[
{"$match": {"borough": "Queens", "cuisine": "Brazilian"}},
{"$group": {"_id": "$address.zipcode", "count": {"$sum": 1}}}
]
)
for document in cursor:
print(document)

mongodb shell 用法

https://docs.mongodb.com/manual/mongo/

启动 mongodb shell

1
2
mongo
mongo --username <user> --password <pass> --host <host> --port 28015

系统全局信息

1
2
3
4
5
6
7
8
9
10
11
# 显示当前使用的数据库名称
db.getName()
# 当前数据库版本
db.version()
# 查看当前数据库的链接机器地址
db.getMongo()
# 显示当前数据库状态,包含数据库名称,集合个数,当前数据库大小
db.stats()

db

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 当前使用的db
db
# 有哪些db
show dbs
db.getSiblingDB()
# 新建/切换db
use myNewDatabase
# 删除当前使用的数据库
db.dropDatabase()
# 修复当前数据库
db.repairDatabase()
# 查看数据库中有那些个集合
db.getCollectionNames()

collection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 新建collection
db.myCollection.insert( { x: 1 } );
# 有哪些collections
show collections
# 其他access方式
db["3test"].insert({ b:2 })
db["3test"].find()
db.getCollection("3test").find()
# 删除单条记录
db.collection.remove()
# 删除collection
db.collection.drop()
# 查询document
db.3test.find({"exclude":false}).count()
db.sv_lsh.find({"exclude":false})[0]["value"][0].length

复杂查询

db.fv_20170210.find({“value”:1929})
PersonModel.find({ favouriteFoods: { “$in” : [“sushi”]} }, …);

db.runCommand({“distinct”: feature_vector_collection_name, “key”: “app_index”})
db.runCommand({“distinct”: db.fv_20170210.find({“value”:1929}),”key”:”app_index”})

var lst = db.fv_20170210.find({“value”:9235});
while(lst.hasNext()) db.test.insert(lst.next());
db.runCommand({“distinct”: “test”, “key”:”app_index”})
db.test.drop()

db.runCommand({“distinct”: “test”, “key”:”app_index”})[“values”].length

聚合

聚合 平均值,求和
http://www.runoob.com/mongodb/mongodb-aggregate.html

1
2
3
4
5
var lst = db.fv_20170210.find();
while(lst.hasNext()) {
var doc = lst.next();
printjson(doc);
}
1
2
3
4
5
var lst = db.fv_20170210.find();
while(lst.hasNext()) {
var doc = lst.next();
db.app_info.insert({"app_index":doc["app_index"],"number":doc["value"].length, "item":"abc"});
}
1
2
3
4
5
6
7
8
9
10
11
db.app_info.aggregate(
[
{
$group:
{
_id: "$item",
avgNumber: { $avg: "$number" }
}
}
]
)

https://docs.mongodb.com/manual/reference/operator/aggregation/avg/

输出

1
2
3
4
5
6
# 美化输出
db.myCollection.find().pretty()
print() to print without formatting
print(tojson(<obj>)) to print with JSON formatting and equivalent to printjson()
printjson() to print with JSON formatting and equivalent to print(tojson(<obj>))

其他

up/down 历史命令

tab 可以autocomplete, 单击或连击两下。

exit 退出

基本概念

MongoDB The Definitive Guide

BSON

在MongoDB中,文档是对数据的抽象,它被使用在Client端和Server端的交互中。所有的Client端(各种语言的Driver)都会使用这种抽象,它的表现形式就是我们常说的BSON(Binary JSON )。

BSON是一个轻量级的二进制数据格式。MongoDB能够使用BSON,并将BSON作为数据的存储存放在磁盘中。

当Client端要将写入文档,使用查询等等操作时,需要将文档编码为BSON格式,然后再发送给Server端。同样,Server端的返回结果也是编码为BSON格式再放回给Client端的。

使用BSON格式出于以下3种目的:

效率

BSON是为效率而设计的,它只需要使用很少的空间。即使在最坏的情况下,BSON格式也比JSON格式再最好的情况下存储效率高。

传输性

在某些情况下,BSON会牺牲额外的空间让数据的传输更加方便。比如,字符串的传输的前缀会标识字符串的长度,而不是在字符串的末尾打上结束的标记。这样的传输形式有利于MongoDB修改传输的数据。

性能

最后,BSON格式的编码和解码都是非常快速的。它使用了C风格的数据表现形式,这样在各种语言中都可以高效地使用。

更多关于BSON的介绍,可以参考:http://www.bsonspec.org。

写入协议

Client端访问Server端使用了轻量级的TCP/IP写入协议。这种协议在MongoDB Wiki中有详细介绍,它其实是在BSON数据上面做了一层简单的包装。比如说,写入数据的命令中包含了1个20字节的消息头(由消息的长度和写入命令标识组成),需要写入的Collection名称和需要写入的数据。

数据文件

在MongoDB的数据文件夹中(默认路径是/data/db)由构成数据库的所有文件。每一个数据库都包含一个.ns文件和一些数据文件,其中数据文件会随着数据量的增加而变多。所以如果有一个数据库名字叫做foo,那么构成foo这个数据库的文件就会由foo.ns,foo.0,foo.1,foo.2等等组成。

数据文件每新增一次,大小都会是上一个数据文件的2倍,每个数据文件最大2G。这样的设计有利于防止数据量较小的数据库浪费过多的空间,同时又能保证数据量较大的数据库有相应的空间使用。

MongoDB会使用预分配方式来保证写入性能的稳定(这种方式可以使用–noprealloc关闭)。预分配在后台进行,并且每个预分配的文件都用0进行填充。这会让MongoDB始终保持额外的空间和空余的数据文件,从而避免了数据增长过快而带来的分配磁盘空间引起的阻塞。

名字空间和盘区

每一个数据库都由多个名字空间组成,每一个名字空间存储了相应类型的数据。数据库中的每一个Collection都有各自对应的名字空间,索引文件同样也有名字空间。所有名字空间的元数据都存储在.ns文件中。

名字空间中的数据在磁盘中分为多个区间,这个叫做盘区。在下图中,foo这个数据库包含3个数据文件,第三个数据文件属于空的预分配文件。头两个数据文件被分为了相应的盘区对应不同的名字空间。

上图显示了名字空间和盘区的相关特点。每一个名字空间可以包含多个不同的盘区,这些盘区并不是连续的。与数据文件的增长相同,每一个名字空间对应的盘区大小的也是随着分配的次数不断增长的。这样做的目的是为了平衡名字空间浪费的空间与保持某一个名字空间中数据的连续性。上图中还有一个需要注意的名字空间:$freelist,这个名字空间用于记录不再使用的盘区(被删除的Collection或索引)。每当名字空间需要分配新的盘区的时候,都会先查看$freelist是否有大小合适的盘区可以使用。

内存映射存储引擎

MongoDB目前支持的存储引擎为内存映射引擎。当MongoDB启动的时候,会将所有的数据文件映射到内存中,然后操作系统会托管所有的磁盘操作。这种存储引擎有以下几种特点:

  • MongoDB中关于内存管理的代码非常精简,毕竟相关的工作已经有操作系统进行托管。

  • MongoDB服务器使用的虚拟内存将非常巨大,并将超过整个数据文件的大小。不用担心,操作系统会去处理这一切。

  • MongoDB无法控制数据写入磁盘的顺序,这样将导致MongoDB无法实现writeahead日志的特性。所以,如果MongoDB希望提供一种durability的特性(这一特性可以参考我写的关于Cassandra文章:http://www.cnblogs.com/gpcuster/tag/Cassandra/),需要实现另外一种存储引擎。

http://blog.csdn.net/yiqijinbu/article/details/9053467
http://www.tuicool.com/articles/iARr2m