zoukankan      html  css  js  c++  java
  • 文档数据库MongoDB

    MongoDB是一个基于分布式文件存储的文档式数据库.其由C++编写, 旨在为Web应用提供可扩展的高性能数据存储解决方案.

    MongoDB中每条数据记录被作为一个文档存储,文档由集合(collection)进行管理, 每个数据库(db)下包含多个集合.

    这与关系型数据库记录,数据表,数据库的关系类似, 但是同一个collection下的文档可以存储格式不同的数据,更加灵活.

    首先我们在Ubuntu上安装MongoDB:

    sudo apt-get install mongodb
    

    MongoDB的数据需要存储在dbpath目录下, MongoDB默认以/data/db作为dbpath.

    该目录不会在安装过程中自动创建, 需要手动chua创建:

    sudo mkdir -p /data/db
    

    启动MongoDB服务:

    mongod
    

    使用dbpath参数指定目录:

    mongod --dbpath path
    

    使用--rest参数启动Web管理界面支持.

    MongoDB Shell是MongoDB自带的交互式Javascript shell:

    mongo
    

    因为这是个js shell可以在这里用js进行交互操作.

    MongoDB默认用27017端口提供服务, Web界面的端口比服务端口多1000, 即28017端口.

    在浏览器中访问http://localhost:28017即可打开MongoDB的Web界面.

    MongoDB中最顶层的容器为数据库(db), 使用show dbs命令查看所有数据库:

    > show dbs
    local	0.078125GB
    

    use指令用于切换到指定数据库, 当该数据库不存在时则自动创建:

    > use test
    switched to db test
    

    成功切换到数据库后, db对象代表当前数据库:

    > db
    test
    

    调用dropDatabase()删除数据库:

    > db.dropDatabase()
    { "dropped" : "test", "ok" : 1 }
    

    访问db对象的成员为集合, 访问一个不存在的集合将会自动创建:

    > db.user
    test.user
    

    若要在创建时指定参数可以使用db.createCollection(name, options)

    调用drop()方法清空集合:

    > db.user.drop()
    true
    

    当集合中不含文档时会被自动删除.

    文档操作

    文档是MongoDB中数据的单位, 每个文档是采用BSON(Binary JSON)存储的字典.

    文档由集合进行管理,

    添加文档

    使用insert()方法添加文档:

    > doc = ({username:'filey', password:'1234'});
    { "username" : "filey", "password" : "1234" }
    > db.user.insert(doc)
    

    save()方法用于保存文档更改, 当文档不存在时自动创建:

    > db.user.insert(doc)
    > db.user.save(doc)
    > db.user.insert(doc)
    E11000 duplicate key error index: test.user.$_id_  dup key: { : ObjectId('57d77ba9a78dc753c19b1cc0') }
    > db.user.save(doc)
    

    查找文档

    find()方法可以查看集合中的文档:

    > db.user.find()
    { "_id" : ObjectId("57d77b87a78dc753c19b1cbf"), "username" : "first", "password" : "1234" }
    { "_id" : ObjectId("57d77ba9a78dc753c19b1cc0"), "username" : "second", "password" : "1234" }
    

    可以根据文档中的属性值进行查询:

    > db.user.find({'username':first})
    { "_id" : ObjectId("57d77b87a78dc753c19b1cbf"), "username" : "first", "password" : "1234" }
    

    pretty()方法可以优化显示:

    > db.user.find().pretty()
    {
        "_id" : ObjectId("57d77b87a78dc753c19b1cbf"),
        "username" : "first",
        "password" : "1234"
    }
    {
        "_id" : ObjectId("57d77ba9a78dc753c19b1cc0"),
        "username" : "second",
        "password" : "1234"
    }
    

    与SQL类似, MongoDB的查询支持更复杂的条件:

    功能 MongoDB SQL
    等于 find({attr:val}) where attr = val
    小于 find({attr:{$lt:val}}) where attr < val
    小于等于 find({attr:{$lte:val}}) where attr <= val
    大于 find({attr:{$gt:val}}) where attr > val
    大于等于 find({attr:{$gte:val}}) where attr >= val
    不等于 find({attr:{$ne:val}}) where attr != val

    可以发现除了最简单的等于外,其它的表达式val都是用字典表示, 字典中的多个键表示与的关系:

    find(attr:{$gt:lower, $gt:upper})
    

    上述表达式等价于: where attr > lower and attr < upper. or条件的表达:

    find({
    	attr: {
        	$or: [
            	{'&lt': upper},
                {'&ne', bidden}
            ]
        }
    })
    

    $type用于根据BSON中的数据类型进行筛选:

    find({attr:{$type:1}})
    

    上面的查询限定了attr的类型为double.

    数字与类型之间的对照见下表:

    1. Double

    2. String

    3. Object

    4. Array

    5. Binary Data

    6. Undefined (已废弃)

    7. ObjectId

    8. Boolean

    9. Date

    10. Null

    删除文档

    remove(query, [option])方法用于删除文档, query与find的参数相同, 用于表达查询条件.

    option是描述选项的字典:

    db.collection.remove(
    	query,
        {
        	justOne: false,
            writeConcern: {}
        }
    )
    

    justOne为true只删除查询到的第一个结果, 否则删除所有结果; writeConern表示日志的级别.

    使用{}表示删除所有文档:

    db.collection.remove({})
    

    更新文档

    除了save方法可以强制更新文档外, update方法可以实现更灵活的文档更新:

    db.collection.update(query, update, [option])
    

    query是表达查询条件的字典, 与find相同.

    update为描述更新操作的字典, 其key有$set$inc等分别代表设置,添加键值对等操作.

    option为表示选项的字典:

    {
    	upsert: false,
        multi: false,
        writeConcern: {}
    }
    

    upsert为true表示在文档不存在时新建文档, 默认为false.

    multi为false时只修改查询到的第一个文档,否则修改查询到的所有文档, 默认为false.

    writeConcern表示日志的级别.

    limit, skip 与 sort

    limit方法用于限制结果集中文档的数量:

    db.collection.find().limit(num)
    

    num表示返回结果集中前num个文档, 若num大于总数则返回整个结果集.

    skip用法与limit类似:

    db.collection..find().skip(num)
    

    num表示跳过结果集中前num个文档, 返回后面的文档.

    limit和skip都是与顺序有关的查询操作, 所以我们需要排序方法和它们配合使用.

    sort方法用于进行排序:

    db.collection.find().sort({key1:1, key2:-1,})
    

    key表示作为排序依据的属性, 1表示升序排列, -1表示降序排列.

    在key1相同的情况下, 按照key2的规则进行排序.

    默认情况下按照objectId进行升序排列.

    aggregate

    聚合(aggregate)操作用于获得集合或结果集的和,平均值等统计量.

    db.collection[.find()].count(query)
    

    count接受一个代表查询规则的字典, 返回满足条件的文档的个数.可以对集合或者结果集应用该方法.

    db.collection.distinct(key)
    

    distinct函数返回所有key指定属性的列表并删除重复:

    > db.user.distinct('username')
    [ "first", "second" ]
    

    distinct只能对集合使用, 不能对结果集使用.

    上面两个函数都只能进行及其简单的聚合操作, aggregate方法可以完成复杂的聚合操作.

    db.collection.aggregate(ops)
    

    ops参数为列表, 其中的元素为代表一次聚合操作的字典. 第一次操作的结果作为第二次操作的输入, 如此形成聚合管道.

    首先准备一个测试集合;

    > db.user.insert({username:'first', score:98})
    > db.user.insert({username:'first', score:88})
    > db.user.insert({username:'second', score:58})
    > db.user.insert({username:'third', score:98})
    > db.user.insert({username:'forth', score:95})
    

    执行聚合管道操作:

    db.user.aggregate([
    	{ $match:
        	{score: {$gte: 60}}
        },
        { $group:
        	{ _id: '$username', avg: {$avg: '$score'} }
        }
    ])
    

    首先执行match操作, 筛选score>=60的文档:

    {username:'first', score:98}
    {username:'first', score:88}
    {username:'third', score:98}
    {username:'forth', score:95}
    

    group操作进一步过滤上述结果集, 按照username分组, 计算每组score的平均值输出为avg:

    "result" : [
            {
                "_id" : "forth",
                "avg" : 95
            },
            {
                "_id" : "third",
                "avg" : 98
            },
            {
                "_id" : "first",
                "avg" : 93
            }
        ],
        "ok" : 1
    }
    

    上述语句等价于SQL语句:

    select avg(score) as "avg"
    from db.user
    where score >= 60;
    

    以上文的键值对$match:{score: {$gte: 60}}为例,$match称为管道操作符, {score: {$gte: 60}称为管道表达式.

    下面介绍一些常用的管道操作:

    $project

    投影, 选择特定属性.其表达式为字典, 键为属性名, 值为1的键被保留,0和未指定的被过滤:

    db.user.aggregate({
    	$project: {
        	_id: 1,
        }
    })
    

    结果:

    {
        "result" : [
            {
                "_id" : ObjectId("57db67663364fa058d0ac911")
            },
        ],
        "ok": 1
    }
    

    $match

    匹配, 筛选特定文档.match的管道表达式与find的query字典相同.

    db.user.aggregate({
        $match: {
            score: {$gte: 60},
        }
    })
    

    结果:

    {
        "result" : [
            {
                "_id" : ObjectId("57db67663364fa058d0ac911"),
                "username" : "first",
                "score" : 98
            },
            {
                "_id" : ObjectId("57db676e3364fa058d0ac912"),
                "username" : "first",
                "score" : 88
            },
        ],
        "ok" : 1
    }
    

    $limit

    限制文档的个数.管道表达式为正整数:

    db.user.aggregate({$limit: 2 })
    

    $skip

    跳过指定个数的文档, 管道表达式为正整数:

    db.user.aggregate({$skip: 2 })
    

    $sort

    对文档按照指定的属性排序, 管道表达式与sort()方法参数一致.

    db.user.aggregate({
        $sort: {score: 1, username: 1}
    })
    

    $unwind

    将含有多值属性的文档拆分为多个只有单值属性的文档:

    >db.article.insert(
    	{
        	name: 'First to MonogoDB',
            author: 'finley',
            tags: ['technology', 'database', 'NoSQl']}
    )
    >db.article.aggregate({$unwind: '$tags'})
    

    $unwind的管道表达式为$加字段名组成的字符串.

    结果:

    {
        "result" : [
            {
                "_id" : ObjectId("57db79f8dbf8a742aa6bc85f"),
                "name" : "First to MonogoDB",
                "author" : "finley",
                "tags" : "technology"
            },
            {
                "_id" : ObjectId("57db79f8dbf8a742aa6bc85f"),
                "name" : "First to MonogoDB",
                "author" : "finley",
                "tags" : "database"
            },
            {
                "_id" : ObjectId("57db79f8dbf8a742aa6bc85f"),
                "name" : "First to MonogoDB",
                "author" : "finley",
                "tags" : "NoSQl"
            }
        ],
        "ok" : 1
    }
    

    unwind的目标字段必须为数组, 否则会产生错误:

    exception: $unwind:  value at end of field path must be an array
    

    $group

    用于分组并进行统计:

    db.user.aggregate(
        { $group:
        	{ _id: '$username', avg: {$avg: '$score'} }
        }
    )
    

    结果:

    "result" : [
    	{
    		"_id" : "forth",
    		"avg" : 95
    	},
    	{
        	"_id" : "third",
    		"avg" : 98
        }
        ],
        "ok" : 1
    }
    

    关系表达式中, _id键是必须的, 指定用于分组的属性, 属性值相同的文档将被分为一组.

    其余键用于指定结果中属性的名称, 其值指定属性的值.

    可以使用的集函数包括:

    • $avg

    • $sum

    • $max

    • $min

    • $first

    • $last

    • $push 将所选属性合并到一个array中

    注意使用$加字段名组成的字符串来指定进行统计的属性.

    索引

    索引可以大幅提高查询数据的效率:

    db.collection.ensureIndex(index, option)
    

    index为一个词典, 其中键为属性名, 值为1或-1.1代表按升序建立索引, -1代表按降序建立索引.

    索引可以建立在单一字段上, 或者在多个字段上建立复合索引.

    option为指定可选参数的字典:

    key type description default
    background bool true: 建立索引时阻塞数据库, false: 后台建立 false
    unique bool 索引字段是否唯一 false
    dropDups bool 创建唯一索引时是否自动删除重复文档 false
    name string 索引的名称 根据索引规则自动创建
    sparse bool 对集合中不存在该字段的文档不创建索引, 使其无法被索引字段查询到 false
    expireAfterSeconds integer 失效时间
    v indexvision 索引版本号 自动
    weights document 索引权重值
    default_language string 对于文本索引, 决定词典规则和停用词 en
  • 相关阅读:
    perl oneline
    perl修改镜像源地址
    pandas 模块
    django学习
    python- shutil 高级文件操作
    小爬虫爬一个贴吧网页的图片
    Python Tkinter的学习
    python的帮助信息的写法
    python3.5+tornado学习
    LinkedList,ArrayList,HashMap,TreeMap
  • 原文地址:https://www.cnblogs.com/Finley/p/5936086.html
Copyright © 2011-2022 走看看