zoukankan      html  css  js  c++  java
  • 爬虫之mongodb数据库

    一 mongodb的介绍

     1、易用性:mongodb是一款强大。灵活并且易扩展的数据库。他面向于文档的数据库,而不是关系性数据库。不采用关系型主要是为了获得更好的扩展性。还有一个好处就是面向文档的数据库不在需要行(row)的概念。通过在文档中嵌入文档和数组,面向文档的方法能够仅使用一条记录来表现复杂的层级关系,这与现代的面向对象语言的开发者对数据的看法一致。 另外,不再有预定义模式(predefined schema):文档的键(key)和值(value)不再是固定的类型和大小。由于没有固定的模式,根据需要添加或删除字段变得更容易了。通常由于开发者能够进行快速迭代,所以开发进程得以加快。而且,实验更容易进行。开发者能尝试大量的数据模型,从中选一个最好的。

     2、易扩展性:应用程序数据集的大小正在以不可思议的速度增长。随着可用带宽的增长和存储器价格的下降,即使是一个小规模的应用程序,需要存储的数据量也可能大的惊人,甚至超出 了很多数据库的处理能力。过去非常罕见的T级数据,现在已经是司空见惯了。 由于需要存储的数据量不断增长,开发者面临一个问题:应该如何扩展数据库,分为纵向扩展和横向扩展,纵向扩展是最省力的做法,但缺点是大型机一般都非常贵,而且 当数据量达到机器的物理极限时,花再多的钱也买不到更强的机器了,此时选择横向扩展更为合适,但横向扩展带来的另外一个问题就是需要管理的机器太多。 MongoDB的设计采用横向扩展。面向文档的数据模型使它能很容易地在多台服务器之间进行数据分割。MongoDB能够自动处理跨集群的数据和负载,自动重新分配文档,以及将 用户的请求路由到正确的机器上。这样,开发者能够集中精力编写应用程序,而不需要考虑如何扩展的问题。如果一个集群需要更大的容量,只需要向集群添加新服务器,MongoDB就会自动将现有的数据向新服务器传送

     3,丰富的功能

    MongoDB作为一款通用型数据库,除了能够创建、读取、更新和删除数据之外,还提供了一系列不断扩展的独特功能
    #1、索引
    支持通用二级索引,允许多种快速查询,且提供唯一索引、复合索引、地理空间索引、全文索引
    
    #2、聚合
    支持聚合管道,用户能通过简单的片段创建复杂的集合,并通过数据库自动优化
    
    #3、特殊的集合类型
    支持存在时间有限的集合,适用于那些将在某个时刻过期的数据,如会话session。类似地,MongoDB也支持固定大小的集合,用于保存近期数据,如日志
    
    #4、文件存储
    支持一种非常易用的协议,用于存储大文件和文件元数据。MongoDB并不具备一些在关系型数据库中很普遍的功能,如链接join和复杂的多行事务。省略
    这些的功能是处于架构上的考虑,或者说为了得到更好的扩展性,因为在分布式系统中这两个功能难以高效地实现
    

      4、卓越的性能:MongoDB的一个主要目标是提供卓越的性能,这很大程度上决定了MongoDB的设计。MongoDB把尽可能多的内存用作缓存cache,视图为每次查询自动选择正确的索引。 总之各方面的设计都旨在保持它的高性能 虽然MongoDB非常强大并试图保留关系型数据库的很多特性,但它并不追求具备关系型数据库的所有功能。只要有可能,数据库服务器就会将处理逻辑交给客户端。这种精简方式的设计是MongoDB能够实现如此高性能的原因之一

     二 MongoDB的基础知识

             

     文档是MongoDB的核心概念,文档就是键值对的一个续集。就相当于python中的有序字典,也就相当于mysql数据库里面的记录。

     注意的是:

    #1、文档中的键/值对是有序的。
    #2、文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
    #3、MongoDB区分类型和大小写。
    #4、MongoDB的文档不能有重复的键。
    #5、文档中的值可以是多种不同的数据类型,也可以是一个完整的内嵌文档。文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
    

      文档的命名规范:

    #1、键不能含有 (空字符)。这个字符用来表示键的结尾。
    #2、.和$有特别的意义,只有在特定环境下才能使用。
    #3、以下划线"_"开头的键是保留的(不是严格要求的)。
    

      2 集合就是一组文档。如果将MongoDB中的一个文档比喻为关系型数据库的一行,那么集合就相当于一张表

    #1、集合存在于数据库中,通常情况下为了方便管理,不同格式和类型的数据应该插入到不同的集合,但其实集合没有固定的结构,这意味着我们完全可以把不同格式和类型的数据统统插入一个集合中。
    
    #2、组织子集合的方式就是使用“.”,分隔不同命名空间的子集合。
    比如一个具有博客功能的应用可能包含两个集合,分别是blog.posts和blog.authors,这是为了使组织结构更清晰,这里的blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何关系。
    在MongoDB中,使用子集合来组织数据非常高效,值得推荐
    
    #3、当第一个文档插入时,集合就会被创建。合法的集合名:
    集合名不能是空字符串""。
    集合名不能含有字符(空字符),这个字符表示集合名的结尾。
    集合名不能以"system."开头,这是为系统集合保留的前缀。
    用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。
    

      3 数据库:在MongoDB中,多个文档组成集合,多个集合可以组成数据库。

    数据库也通过名字来标识。数据库名可以是满足以下条件的任意UTF-8字符串:
    #1、不能是空字符串("")。
    #2、不得含有' '(空格)、.、$、/、和 (空字符)。
    #3、应全部小写。
    #4、最多64字节。
    
    有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
    #1、admin: 从身份认证的角度讲,这是“root”数据库,如果将一个用户添加到admin数据库,这个用户将自动获得所有数据库的权限。再者,一些特定的服务器端命令也只能从admin数据库运行,如列出所有数据库或关闭服务器
    #2、local: 这个数据库永远都不可以复制,且一台服务器上的所有本地集合都可以存储在这个数据库中
    #3、config: MongoDB用于分片设置时,分片信息会存储在config数据库中
    

      4 强调:把数据库名添加到集合名前,得到集合的完全限定名,即命名空间。如下:

    如果要使用cms数据库中的blog.posts集合,这个集合的命名空间就是
    cmd.blog.posts。命名空间的长度不得超过121个字节,且在实际使用中应该小于100个字节

    三 安装

     下载网址:https://www.mongodb.com/download-center#community

    注意:在 MongoDB 2.2 版本后已经不再支持 Windows XP 系统。最新版本也已经没有了 32 位系统的安装文件。

        MongoDB for Windows 64-bit 适合 64 位的 Windows Server 2008 R2, Windows 7 , 及最新版本的 Window 系统。
        MongoDB for Windows 32-bit 适合 32 位的 Window 系统及最新的 Windows Vista。 32 位系统上 MongoDB 的数据库最大为 2GB。
        MongoDB for Windows 64-bit Legacy 适合 64 位的 Windows Vista, Windows Server 2003, 及 Windows Server 2008 。
    

     1 安装:根据你的系统下载 32 位或 64 位的 .msi 文件,下载后双击该文件,按操作提示安装即可。安装过程中,你可以通过点击 "Custom(自定义)" 按钮来设置你的安装目录。

     

    创建数据目录
    
    MongoDB将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该放在根目录下((如: C: 或者 D: 等 )。
    
    在本教程中,我们已经在 C 盘安装了 mongodb,现在让我们创建一个 data 的目录然后在 data 目录里创建 db 目录。
    

      解压,讲bin目录加入环境变量

     新建文件和目录如下:

    ......datadb
    ......datalog
    ......datalogmongod.log
    

      新建配置文件mongod.cfg,参考:

    网址:https://docs.mongodb.com/manual/reference/configuration-options/
    
    systemLog:
       destination: file
       path: "c:datalogmongod.log"
       logAppend: true
    storage:
       journal:
          enabled: true
       dbPath: "c:datadb"
    net:
       bindIp: 0.0.0.0
       port: 27017
    setParameter:
       enableLocalhostAuthBypass: false
    

      制作系统服务:

    mongod --config "C:mongodbmongod.cfg" --bind_ip 0.0.0.0 --install
    

      启动关闭:

    net start MongoDB
    net stop MongoDB
    

      登陆:

    mongo
    

      借鉴网址:http://www.runoob.com/mongodb/mongodb-window-install.html

     账户管理:

    #账号管理:https://docs.mongodb.com/master/tutorial/enable-authentication/
    #1、创建账号
    use admin
    db.createUser(
      {
        user: "root",
        pwd: "123",
        roles: [ { role: "root", db: "admin" } ]
      }
    )
    
    use test
    db.createUser(
      {
        user: "egon",
        pwd: "123",
        roles: [ { role: "readWrite", db: "test" },
                 { role: "read", db: "db1" } ]
      }
    )
    
    
    #2、重启数据库,auth设置管理员权限
    mongod --remove
    mongod --config "C:mongodbmongod.cfg" --bind_ip 0.0.0.0 --install --auth
    
    #3、登录:注意使用双引号而非单引号
    mongo --port 27017 -u "root" -p "123" --authenticationDatabase "admin"
    
    也可以在登录之后用db.auth("账号","密码")登录
    mongo
    use admin
    db.auth("root","123")
    
    #推荐博客:https://www.cnblogs.com/zhoujinyi/p/4610050.html
    View Code

     启动服务端还有在这种方法:

    E:MongoDBServer3.6inmongod --dbpath E:MongoDBServer3.6datadb
    

      注意:在不同的库之间需要创建不同的用户名进行操作,用户名不可以越库操作。

     命令行shell

    #1、mongo 127.0.0.1:27017/config #连接到任何数据库config
    
    #2、mongo --nodb #不连接到任何数据库
    
    #3、启动之后,在需要时运行new Mongo(hostname)命令就可以连接到想要的mongod了:
    > conn=new Mongo('127.0.0.1:27017')
    connection to 127.0.0.1:27017
    > db=conn.getDB('admin')
    admin
    
    #4、help查看帮助
    
    #5、mongo时一个简化的JavaScript shell,是可以执行JavaScript脚本的
    View Code

    四 基本的数据类型

    1、在概念上,MongoDB的文档与Javascript的对象相近,因而可以认为它类似于JSON。JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证明了这点),且仅包含六种数据类型。

    2、这样有很多好处:易于理解、易于解析、易于记忆。然而从另一方面说,因为只有null、布尔、数字、字符串、数字和对象这几种数据类型,所以JSON的表达能力有一定的局限。

    3、虽然JSON具备的这些类型已经具有很强的表现力,但绝大数应用(尤其是在于数据库打交道时)都还需要其他一些重要的类型。例如,JSON没有日期类型,这使得原本容易日期处理变得烦人。另外,JSON只有一种数字类型,无法区分浮点数和整数,更别区分32位和64位了。再者JSON无法表示其他一些通用类型,如正则表达式或函数。

    4、MongoDB在保留了JSON基本键/值对特性的基础上,添加了其他一些数据类型。在不同的编程语言下,这些类型的确切表示有些许差异。下面说明了MongoDB支持的其他通用类型,以及如何正在文档中使用它们

    #1、null:用于表示空或不存在的字段
    d={'x':null}
    #2、布尔型:true和false
    d={'x':true,'y':false}
    #3、数值
    d={'x':3,'y':3.1415926}
    #4、字符串
    d={'x':'egon'}
    #5、日期
    d={'x':new Date()}
    d.x.getHours()
    #6、正则表达式
    d={'pattern':/^egon.*?nb$/i}
    
    正则写在//内,后面的i代表:
    i 忽略大小写
    m 多行匹配模式
    x 忽略非转义的空白字符
    s 单行匹配模式
    
    #7、数组
    d={'x':[1,'a','v']}
    
    #8、内嵌文档
    user={'name':'egon','addr':{'country':'China','city':'YT'}}
    user.addr.country
    
    #9、对象id:是一个12字节的ID,是文档的唯一标识,不可变
    d={'x':ObjectId()}
    

     5、_id和ObjectId

    五CRUD操作

     基础命令:

      show dbs:查看所有的库

         use 库名:切换库

      db:设置库的变量

      ...help:查看使用方法

    help:             库的使用方法
    db.help:        集合的使用方法
    db.表名.help:   文档的操作方法
    

     库的操作:

    #1、增
    use config #如果数据库不存在,则创建数据库,否则切换到指定数据库。
    
    #2、查
    show dbs #查看所有
    可以看到,我们刚创建的数据库config并不在数据库的列表中, 要显示它,我们需要向config数据库插入一些数据。
    db.table1.insert({'a':1})
    
    #3、删
    use config #先切换到要删的库下
    db.dropDatabase() #删除当前库
    

      集合的操作:

    #1、增
    当第一个文档插入时,集合就会被创建
    > use database1
    switched to db database1
    > db.table1.insert({'a':1})
    WriteResult({ "nInserted" : 1 })
    > db.table2.insert({'b':2})
    WriteResult({ "nInserted" : 1 })
    
    #2、查
    > show tables
    table1
    table2
    
    #3、删
    > db.table1.drop()
    true
    > show tables
    table2
    

      文档的操作:

      增:

    #创建一个user的局部变量,这是一个JavaScript对象
    user={
        "name":"egon",
        'is_nb':true,
        'hobbies':['music','read','dancing']
    }
    
    db.userinfo.insert(user)
    db.userinfo.find()
    
    
    user1={
        "name":"asb",
        'is_sb':true,
        'hobbies':['music','read','dancing']
    }
    user2={
        "name":"egon",
        'is_sb':'wxx',
        'hobbies':['music','read','dancing']
    }
    
    user3={
        "name":"egon3",
        'is_sb':false,
        'hobbies':['music','read','dancing']
    }
    db.userinfo.insertMany([user1,user2,user3])
    View Code

      改:

      upate方法:

    update() 方法用于更新已存在的文档。语法格式如下:
    db.collection.update(
       <query>,
       <update>,
       {
         upsert: <boolean>,
         multi: <boolean>,
         writeConcern: <document>
       }
    )
    参数说明:对比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18;
    
    query : 相当于where条件。
    update : update的对象和一些更新的操作符(如$,$inc...等,相当于set后面的
    upsert : 可选,默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入。
    multi : 可选,默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录。
    writeConcern :可选,抛出异常的级别。
    
    更新操作是不可分割的:若两个更新同时发送,先到达服务器的先执行,然后执行另外一个,不会破坏文档。
    View Code

      简单更新:

    #1、最简单的更新就是用一个新的文档完全替换匹配的文档。这适用于大规模式迁移的情况。例如对下面的用户文档做
    一个比较大的调整
    > db.user.find().pretty()
    {
        "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"),
        "name" : "egon",
        "girl_friends" : 33,
        "wives" : 23
    }
    
    
    # 先找到要修改的对象
    > var egon=db.user.findOne({'name':'egon'})
    > egon
    {
        "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"),
        "name" : "egon",
        "girl_friends" : 33,
        "wives" : 23
    }
    # 修改
    > egon.ralationship={'girl_friends':33,'wives':23}
    { "girl_friends" : 33, "wives" : 23 }
    > egon.username=egon.name
    egon
    
    # 删掉没有用的
    > delete egon.girl_friends
    true
    > delete egon.wives
    true
    > delete egon.name
    true
    
    # 完成更新
    > db.user.update({'name':'egon'},egon)
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("5a5b3a74c126b4b2cbb57e3f"), "ralationship" : { "girl_friends" : 33, "wives" : 23 }, "username" : "egon" }
    View Code

      一个常见的在错误:

    2、一个常见的错误
    db.user.insert({'name':'egon','age':10})
    db.user.insert({'name':'egon','age':20})
    db.user.insert({'name':'egon','age':30})
    > db.user.find()
    { "_id" : ObjectId("5a5b3ecac126b4b2cbb57e43"), "name" : "egon", "age" : 10 }
    { "_id" : ObjectId("5a5b3ecbc126b4b2cbb57e44"), "name" : "egon", "age" : 20 }
    { "_id" : ObjectId("5a5b3ecdc126b4b2cbb57e45"), "name" : "egon", "age" : 30 }
    
    # 找到的是第二个egon,他要过生日,于是长了一岁
    > var obj=db.user.findOne({'name':'egon','age':20})
    > obj.age++
    
    
    # 我们的条件只定位到第二条记录这一条记录,所以更新是没问题的,
    > db.user.update({'name':'egon','age':20},obj)
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    
    # 我们的条件定位到了多条记录,而obj对象的_id是一定的,文档中的_id是唯一的,我们无法将三条改成同一个_id,所以报错
    > db.user.update({'name':'egon'},obj) #报错
    
    # 删掉后,更新成功,但默认改的是第一条
    > delete obj._id
    true
    > obj
    { "name" : "egon", "age" : 21 }
    > db.user.update({'name':'egon'},obj)
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("5a5b40f6c126b4b2cbb57e46"), "name" : "egon", "age" : 21 }
    { "_id" : ObjectId("5a5b40f6c126b4b2cbb57e47"), "name" : "egon", "age" : 20 }
    { "_id" : ObjectId("5a5b40f6c126b4b2cbb57e48"), "name" : "egon", "age" : 30 }
    > 
    
    # 所以针对这种情况,我们还以_id作为条件保证只定位到我们想要修改的对象,并且比起随机字符串,_id的查找速度更快
    > db.user.update({'_id':ObjectId("5a5b40f6c126b4b2cbb57e47")},obj)
    
    # ps: 改多条
    > db.user.update({'name':'egon'},obj,{'multi':true})
    WriteResult({
        "nMatched" : 0,
        "nUpserted" : 0,
        "nModified" : 0,
        "writeError" : {
            "code" : 9,
            "errmsg" : "multi update only works with $ operators" #只能用修改器
        }
    })
    > db.user.update({'name':'egon'},{$set:obj},{'multi':true})
    WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 1 })
    View Code

      使用修改器:

    通常文档只会有一部分需要更新。可以使用原子性的更新修改器,指定对文档中的某些字段进行更新。
    更新修改器是种特殊的键,用来指定复杂的更新操作,比如修改、增加后者删除
    
    #=======>1、"$set"修改器
    > db.user.find()
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "name" : "egon", "age" : 10 }
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 20 }
    { "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }
    #完全覆盖原文档
    > db.user.update({'_id':ObjectId("5a5b51a257147a04b81f2bb4")},{'age':111})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 20 }
    { "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }
    >
    
    #$set只更新原文档的一部分
    > db.user.update({'_id':ObjectId("5a5b51a257147a04b81f2bb5")},{'$set':{'age':222}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 222 }
    { "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30 }
    
    # 有则更新,无则新增
    > db.user.update({'age':30},{'$set':{'addr':{'country':'China','city':'BJ'}}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.user.find()
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb4"), "age" : 111 }
    { "_id" : ObjectId("5a5b51a257147a04b81f2bb5"), "name" : "egon", "age" : 222 }
    { "_id" : ObjectId("5a5b51a357147a04b81f2bb6"), "name" : "egon", "age" : 30, "addr" : { "country" : "China", "city" : "BJ" } }
    
    
    # 修改内嵌文档
    db.user.update({'age':30},{'$set':{'addr.country':'CHINA'}})
    
    # $unset
    db.user.update({'age':30},{'$unset':{'addr':'什么值都行'}})
    
    
    
    #=======>2、增加和减少
    "$inc"修改器用来增加已经有的键的值(负数则为减少),或者该键不存在那就创建一个。只能用于整型、长整型或双浮点
    的值。
    对于更新分析数据、因果关系、投票或者其他有变化数值的地方,使用这个都会非法方便
    
    
    例如:
    > db.analytics.find()
    { "_id" : ObjectId("5a5b4cb2126d610970c553ab"), "url" : "http://www.baidu.com", "pv" : 2 }
    > db.analytics.update({'url':'http://www.baidu.com'},{'$inc':{'pv':1}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.analytics.find()
    { "_id" : ObjectId("5a5b4cb2126d610970c553ab"), "url" : "http://www.baidu.com", "pv" : 3 }
    使用修改器时,_id的值不能改变。其他的键值,包括其他的唯一索引的键,都是可以更改的。
    注意:整个文档替换时可以改变_id
    
    
    
    #=======>3、往数组内添加元素
    如果数组已经存在,"$push"会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。
    例如提交博客的评论
    
    db.blog.insert({'_id':1,'name':'alex意外死亡的真相'})
    
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是谁???'}}})
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的'}}})
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖赌抽,欠下两个亿'}}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "egon",
                            "content" : "alex是谁???"
                    },
                    {
                            "name" : "wxx",
                            "content" : "我去,真的假的"
                    },
                    {
                            "name" : "yxx",
                            "content" : "吃喝嫖赌抽,欠下两个亿"
                    }
            ]
    }
    
    # 一次加多个"$push"
    db.blog.update({'_id':1},{'$push':{'comments':{'$each':[{'name':'oldboy','content':'鼓掌'},{'name':'oldgirl','content':'一鞠躬'}]}}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "egon",
                            "content" : "alex是谁???"
                    },
                    {
                            "name" : "wxx",
                            "content" : "我去,真的假的"
                    },
                    {
                            "name" : "yxx",
                            "content" : "吃喝嫖赌抽,欠下两个亿"
                    },
                    {
                            "name" : "oldboy",
                            "content" : "鼓掌"
                    },
                    {
                            "name" : "oldgirl",
                            "content" : "一鞠躬"
                    }
            ]
    }
    
    
    # 限制大小"$slice",只留最后n个
    db.blog.update({'_id':1},{'$push':{'comments':{'$each':[
        {'name':'xxx','content':'二鞠躬'},
        {'name':'yyy','content':'三鞠躬'},
        {'name':'yyy','content':'四鞠躬'},
        {'name':'zzz','content':'五鞠躬'},
        {'name':'mmm','content':'六鞠躬'},
        {'name':'nnn','content':'七鞠躬'},
        ],
        '$slice':-7
    }}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "oldgirl",
                            "content" : "一鞠躬"
                    },
                    {
                            "name" : "xxx",
                            "content" : "二鞠躬"
                    },
                    {
                            "name" : "yyy",
                            "content" : "三鞠躬"
                    },
                    {
                            "name" : "yyy",
                            "content" : "四鞠躬"
                    },
                    {
                            "name" : "zzz",
                            "content" : "五鞠躬"
                    },
                    {
                            "name" : "mmm",
                            "content" : "六鞠躬"
                    },
                    {
                            "name" : "nnn",
                            "content" : "七鞠躬"
                    }
            ]
    }
    
    
    
    
    #=======>4、The $sort element value must be either 1 or -1"
    # '$sort':{'name': 1}升序排
    db.blog.update({'_id':1},{'$push':{'comments':{'$each':[
        {'name':'aaa','content':'礼毕'},
        ],
        '$slice':-3,
        '$sort':{'name': 1}
    }}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "yyy",
                            "content" : "三鞠躬"
                    },
                    {
                            "name" : "yyy",
                            "content" : "四鞠躬"
                    },
                    {
                            "name" : "zzz",
                            "content" : "五鞠躬"
                    }
            ]
    }
    
    # '$sort':{'name': -1} 降序排
    db.blog.update({'_id':1},{'$push':{'comments':{'$each':[
        {'name':'aaa','content':'礼毕'},
        ],
        '$slice':-2,
        '$sort':{'name': -1}
    }}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "yyy",
                            "content" : "四鞠躬"
                    },
                    {
                            "name" : "aaa",
                            "content" : "礼毕"
                    }
            ]
    }
    
    
    #注意:不能只将"$slice"或者"$sort"与"$push"配合使用,且必须使用"$eah"
    
    
    
    #=======>5、避免添加重复 "$addToSet"
    > db.urls.insert({'_id':1,'urls':[]})
    WriteResult({ "nInserted" : 1 })
    > db.urls.find()
    { "_id" : 1, "urls" : [ ] }
    
    db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.baidu.com'}})
    db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.baidu.com'}})
    db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.baidu.com'}})
    db.urls.update({'_id':1},{'$addToSet':{'urls':'http://www.python.org'}})
    > db.urls.find()
    { "_id" : 1, "urls" : [ "http://www.baidu.com", "http://www.python.org" ] }
    
    
    db.urls.update({'_id':1},{
        '$addToSet':{
            'urls':{
                    '$each':['http://www.baidu.com','http://www.baidu.com','http://www.xxx.com']
                }
        }
    })
    > db.urls.find()
    { "_id" : 1, "urls" : [ "http://www.baidu.com", "http://www.python.org", "http://www.xxx.com" ] }
    
    
    #=======>6、删除元素
    如果把数组看成是队列或者栈,可以用"$pop",这个修改器可以从数组任何一端删除元素。
    {"$pop":{"key":1}} 从数组末尾删除一个元素
    {"$pop":{"key":-1}} 从头部删除
    
    
    > db.queue.insert({'_id':1,'queue':[]})
    WriteResult({ "nInserted" : 1 })
    # 入队列
    db.queue.update({'_id':1},{'$push':{'queue':'alex'}})
    db.queue.update({'_id':1},{'$push':{'queue':'egon'}})
    db.queue.update({'_id':1},{'$push':{'queue':'wxx'}})
    db.queue.update({'_id':1},{'$push':{'queue':'yxx'}})
    
    > db.queue.find()
    { "_id" : 1, "queue" : [ "alex", "egon", "wxx", "yxx" ] }
    
    # 出队列
    db.queue.update({'_id':1},{"$pop":{"queue":-1}})
    db.queue.update({'_id':1},{"$pop":{"queue":-1}})
    db.queue.update({'_id':1},{"$pop":{"queue":-1}})
    
    
    # "$pull" 把符合条件的统统删掉,而$pop只能按照位置删除
    db.queue.update({'_id':1},{"$pull":{"queue":'yxx'}})
    
    
    
    
    #=======>7、基于位置的数组修改器
    db.blog.insert({'_id':1,'name':'alex意外死亡的真相'})
    
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"egon","content":'alex是谁???','thumb':20}}})
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"wxx","content":'我去,真的假的','thumb':30}}})
    db.blog.update({'_id':1},{'$push':{'comments':{"name":"yxx","content":'吃喝嫖赌抽,欠下两个亿','thumb':40}}})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "egon",
                            "content" : "alex是谁???",
                            "thumb" : 20
                    },
                    {
                            "name" : "wxx",
                            "content" : "我去,真的假的",
                            "thumb" : 30
                    },
                    {
                            "name" : "yxx",
                            "content" : "吃喝嫖赌抽,欠下两个亿",
                            "thumb" : 40
                    }
            ]
    }
    
    根据下标修改
    db.blog.update({'_id':1},{'$set':{'comments.0.thumb':200}})
    
    
    必须查询才知道下表,所以提供了$,$ 代表根据条件匹配出的元素
    db.blog.update({'comments.name':'wxx'},{'$set':{'comments.$.thumb':300}})
    
    
    
    #=======>8、upsert与multi
    db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true ) #全部添加加进去
    View Code

      查:

    db.userinfo.findOne()
    # 查找所有
    db.userinfo.find()
    db.userinfo.find().pretty()
    
    # 多个and条件
    db.user.find({'name':'egon','age':{'$gt':20}})
    
    # 也可不写条件,代表匹配所有
    db.user.find({})
    
    # 规定显示结果中有哪些key没有哪些key
    > db.user.find({},{'_id':0,'name':1,'age':1})
    { "name" : "egon", "age" : 10 }
    { "name" : "egon", "age" : 20 }
    { "name" : "egon", "age" : 30 }
    
    # "$lt" "lte" "$gt" "gte" "$ne",其中"$ne"能用于所有数据类型
    db.user.find({'age':{'$gte':10,'$lt':30}})
    
    # or查询,or的条件放到[]内,注意:一个{}内逗号分开的多个条件相当于and
    db.user.find({'$or':[{'name':'egon'},{'age':{'$gte':30}}]})
    
    # in和nin
    db.user.find({'age':{'$in':[10,11,12,20]}})
    db.user.find({'age':{'$nin':[10,11,12,20]}})
    
    # {'$mod':[2,1]},对2取余如果为1则匹配成功
    db.user.insert({'_id':1,'name':'egon','age':10})
    db.user.insert({'_id':2,'name':'egon','age':20})
    db.user.insert({'_id':3,'name':'egon','age':30})
    
    > db.user.find()
    { "_id" : 1, "name" : "egon", "age" : 10 }
    { "_id" : 2, "name" : "egon", "age" : 20 }
    { "_id" : 3, "name" : "egon", "age" : 30 }
    
    > db.user.find({'_id':{'$mod':[2,1]}})
    { "_id" : 1, "name" : "egon", "age" : 10 }
    { "_id" : 3, "name" : "egon", "age" : 30 }
    
    # not 取反
    > db.user.find({'_id':{'$not':{'$mod':[2,1]}}})
    { "_id" : 2, "name" : "egon", "age" : 20 }
    
    # {'key':null} 匹配key的值为null或者没有这个key
    
    # 正则表达式
    > db.user.find({'name':/^e.*?n$/i})
    { "_id" : 1, "name" : "egon", "age" : 10 }
    { "_id" : 2, "name" : "egon", "age" : 20 }
    { "_id" : 3, "name" : "egon", "age" : 30 }
    
    # 查询数组
    > db.food.insert({'fruit':['apple','banana','peach']})
    WriteResult({ "nInserted" : 1 })
    > db.food.find({'fruit':'banana'}) #只要存在就可以
    { "_id" : ObjectId("5a5b7ad057147a04b81f2bc3"), "fruit" : [ "apple", "banana", "peach" ] }
    
    > db.food.find({'fruit':{'$all':['banana','apple']}}) #既有banana又有apple
    
    > db.food.find({'fruit.1':'banana'}) #按照位置
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "egon",
                            "content" : "alex是谁???",
                            "thumb" : 200
                    },
                    {
                            "name" : "wxx",
                            "content" : "我去,真的假的",
                            "thumb" : 300
                    },
                    {
                            "name" : "yxx",
                            "content" : "吃喝嫖赌抽,欠下两个亿",
                            "thumb" : 40
                    },
                    {
                            "name" : "egon",
                            "content" : "xxx",
                            "thumb" : 0
                    }
            ]
    }
    db.blog.find({},{'comments':{"$slice":-2}}).pretty() #查询最后两个
    db.blog.find({},{'comments':{"$slice":[1,2]}}).pretty() #查询1到2
    
    
    
    # 数组和范围查询的相互作用
    db.test.insert({'x':5})
    db.test.insert({'x':15})
    db.test.insert({'x':25})
    db.test.insert({'x':[5,25]})
    
    > db.test.find({'x':{'$gt':10,'$lt':20}})
    { "_id" : ObjectId("5a5b8310b9b1b7388a40f993"), "x" : 15 }
    { "_id" : ObjectId("5a5b8310b9b1b7388a40f995"), "x" : [ 5, 25 ] }
    #发现连非数组的也找出来了,如果只想匹配数组,则用$elemMatch
    > db.test.find({'x':{"$elemMatch":{'$gt':10,'$lt':20}}}) #匹配不到内容
    > db.test.find({'x':{"$elemMatch":{'$gt':5,'$lt':115}}}) #25属于该范围
    { "_id" : ObjectId("5a5b8310b9b1b7388a40f995"), "x" : [ 5, 25 ] }
    
    #如果只想匹配非数组需要建立索引,结合min与max使用
    View Code

      删:

    db.userinfo.deleteOne({ 'is_sb': true }) #删除多个中的第一个
    db.userinfo.find()
    db.userinfo.deleteMany( { 'x'': 1 } ) # 删除x=1的全部
    db.userinfo.deleteMany({}) #删除全部
    View Code

     补充查询:

      比较运算符查询:

    # SQL:=,!=,>,<,>=,<=
    # MongoDB:{key:value}代表什么等于什么,"$ne","$gt","$lt","gte","lte",其中"$ne"能用于所有数据类型
    
    #1select * from db1.user where name = "alex";
    db.user.find({'name':'alex'})
    
    #2select * from db1.user where name != "alex";
    db.user.find({'name':{"$ne":'alex'}})
    
    #3select * from db1.user where id > 2;
    db.user.find({'_id':{'$gt':2}})
    
    #4select * from db1.user where id < 3;
    db.user.find({'_id':{'$lt':3}})
    
    #5select * from db1.user where id >= 2;
    db.user.find({"_id":{"$gte":2,}})
    
    #6select * from db1.user where id <= 2;
    db.user.find({"_id":{"$lte":2}})
    View Code

      逻辑运算查询:

    # SQL:andornot
    # MongoDB:字典中逗号分隔的多个条件是and关系,"$or"的条件放到[]内,"$not"
    
    #1select * from db1.user where id >= 2 and id < 4;
    db.user.find({'_id':{"$gte":2,"$lt":4}})
    
    #2select * from db1.user where id >= 2 and age < 40;
    db.user.find({"_id":{"$gte":2},"age":{"$lt":40}})
    
    #3select * from db1.user where id >= 5 or name = "alex";
    db.user.find({
        "$or":[
            {'_id':{"$gte":5}},
            {"name":"alex"}
            ]
    })
    
    #4select * from db1.user where id % 2=1;
    db.user.find({'_id':{"$mod":[2,1]}})
    
    #5、上题,取反
    db.user.find({'_id':{"$not":{"$mod":[2,1]}}})
    View Code

      成员运算查询:

    # SQL:innot in
    # MongoDB:"$in","$nin"
    
    #1select * from db1.user where age in (20,30,31);
    db.user.find({"age":{"$in":[20,30,31]}})
    
    #2select * from db1.user where name not in ('alex','yuanhao');
    db.user.find({"name":{"$nin":['alex','yuanhao']}})
    View Code

      正则匹配查询:

    # SQL: regexp 正则
    # MongoDB: /正则表达/i
    
    #1select * from db1.user where name regexp '^j.*?(g|n)$';
    db.user.find({'name':/^j.*?(g|n)$/i})
    View Code

      查看指定字段:

    #1select name,age from db1.user where id=3;
    db.user.find({'_id':3},{'_id':0,'name':1,'age':1})
    View Code

      查询数组:

    #1、查看有dancing爱好的人
    db.user.find({'hobbies':'dancing'})
    
    #2、查看既有dancing爱好又有tea爱好的人
    db.user.find({
        'hobbies':{
            "$all":['dancing','tea']
            }
    })
    
    #3、查看第4个爱好为tea的人
    db.user.find({"hobbies.3":'tea'})
    
    #4、查看所有人最后两个爱好
    db.user.find({},{'hobbies':{"$slice":-2},"age":0,"_id":0,"name":0,"addr":0})
    
    #5、查看所有人的第2个到第3个爱好
    db.user.find({},{'hobbies':{"$slice":[1,2]},"age":0,"_id":0,"name":0,"addr":0})
    
    > db.blog.find().pretty()
    {
            "_id" : 1,
            "name" : "alex意外死亡的真相",
            "comments" : [
                    {
                            "name" : "egon",
                            "content" : "alex是谁???",
                            "thumb" : 200
                    },
                    {
                            "name" : "wxx",
                            "content" : "我去,真的假的",
                            "thumb" : 300
                    },
                    {
                            "name" : "yxx",
                            "content" : "吃喝嫖赌抽,欠下两个亿",
                            "thumb" : 40
                    },
                    {
                            "name" : "egon",
                            "content" : "xxx",
                            "thumb" : 0
                    }
            ]
    }
    db.blog.find({},{'comments':{"$slice":-2}}).pretty() #查询最后两个
    db.blog.find({},{'comments':{"$slice":[1,2]}}).pretty() #查询1到2
    View Code

      排序查询:

    # 排序:--1代表升序,-1代表降序
    db.user.find().sort({"name":1,})
    db.user.find().sort({"age":-1,'_id':1})
    View Code

      分页查询:

    # 分页:--limit代表取多少个document,skip代表跳过前多少个document。 
    db.user.find().sort({'age':1}).limit(1).skip(2)
    View Code

      查询数量:

    # 获取数量
    db.user.count({'age':{"$gt":30}}) 
    
    --或者
    db.user.find({'age':{"$gt":30}}).count()
    View Code

      其他查询方法:

    #1、{'key':null} 匹配key的值为null或者没有这个key
    db.t2.insert({'a':10,'b':111})
    db.t2.insert({'a':20})
    db.t2.insert({'b':null})
    
    > db.t2.find({"b":null})
    { "_id" : ObjectId("5a5cc2a7c1b4645aad959e5a"), "a" : 20 }
    { "_id" : ObjectId("5a5cc2a8c1b4645aad959e5b"), "b" : null }
    
    #2、查找所有
    db.user.find() #等同于db.user.find({})
    db.user.find().pretty()
    
    #3、查找一个,与find用法一致,只是只取匹配成功的第一个
    db.user.findOne({"_id":{"$gt":3}})
    View Code

     补充修改:

      update语法介绍:

    update() 方法用于更新已存在的文档。语法格式如下:
    db.collection.update(
       <query>,
       <update>,
       {
         upsert: <boolean>,
         multi: <boolean>,
         writeConcern: <document>
       }
    )
    参数说明:对比update db1.t1 set name='EGON',sex='Male' where name='egon' and age=18;
    
    query : 相当于where条件。
    update : update的对象和一些更新的操作符(如$,$inc...等,相当于set后面的
    upsert : 可选,默认为false,代表如果不存在update的记录不更新也不插入,设置为true代表插入。
    multi : 可选,默认为false,代表只更新找到的第一条记录,设为true,代表更新找到的全部记录。
    writeConcern :可选,抛出异常的级别。
    
    更新操作是不可分割的:若两个更新同时发送,先到达服务器的先执行,然后执行另外一个,不会破坏文档。
    View Code

      覆盖式:

    #注意:除非是删除,否则_id是始终不会变的
    #1、覆盖式:
    db.user.update({'age':20},{"name":"Wxx","hobbies_count":3})
    是用{"_id":2,"name":"Wxx","hobbies_count":3}覆盖原来的记录
    
    #2、一种最简单的更新就是用一个新的文档完全替换匹配的文档。这适用于大规模式迁移的情况。例如
    var obj=db.user.findOne({"_id":2})
    
    obj.username=obj.name+'SB'
    obj.hobbies_count++
    delete obj.age
    
    db.user.update({"_id":2},obj)
    View Code

      设置:$set:

    #设置:$set
    
    通常文档只会有一部分需要更新。可以使用原子性的更新修改器,指定对文档中的某些字段进行更新。
    更新修改器是种特殊的键,用来指定复杂的更新操作,比如修改、增加后者删除
    
    #1update db1.user set  name="WXX" where id = 2
    db.user.update({'_id':2},{"$set":{"name":"WXX",}})
    
    #2、没有匹配成功则新增一条{"upsert":true}
    db.user.update({'_id':6},{"$set":{"name":"egon","age":18}},{"upsert":true})
    
    #3、默认只改匹配成功的第一条,{"multi":改多条}
    db.user.update({'_id':{"$gt":4}},{"$set":{"age":28}})
    db.user.update({'_id':{"$gt":4}},{"$set":{"age":38}},{"multi":true})
    
    #4、修改内嵌文档,把名字为alex的人所在的地址国家改成Japan
    db.user.update({'name':"alex"},{"$set":{"addr.country":"Japan"}})
    
    #5、把名字为alex的人的地2个爱好改成piao
    db.user.update({'name':"alex"},{"$set":{"hobbies.1":"piao"}})
    
    #6、删除alex的爱好,$unset
    db.user.update({'name':"alex"},{"$unset":{"hobbies":""}})
    View Code

      增加和减少:$inc

    #增加和减少:$inc
    
    #1、所有人年龄增加一岁
    db.user.update({},
        {
            "$inc":{"age":1}
        },
        {
            "multi":true
        }
        )
    #2、所有人年龄减少5岁
    db.user.update({},
        {
            "$inc":{"age":-5}
        },
        {
            "multi":true
        }
        )
    View Code

      添加和删除数组里面的元素:$push,$pop,$pull

    #添加删除数组内元素
        
    往数组内添加元素:$push
    #1、为名字为yuanhao的人添加一个爱好read
    db.user.update({"name":"yuanhao"},{"$push":{"hobbies":"read"}})
    
    #2、为名字为yuanhao的人一次添加多个爱好tea,dancing
    db.user.update({"name":"yuanhao"},{"$push":{
        "hobbies":{"$each":["tea","dancing"]}
    }})
    
    按照位置且只能从开头或结尾删除元素:$pop
    #3、{"$pop":{"key":1}} 从数组末尾删除一个元素
    
    db.user.update({"name":"yuanhao"},{"$pop":{
        "hobbies":1}
    })
    
    #4、{"$pop":{"key":-1}} 从头部删除
    db.user.update({"name":"yuanhao"},{"$pop":{
        "hobbies":-1}
    })
    
    #5、按照条件删除元素,:"$pull" 把符合条件的统统删掉,而$pop只能从两端删
    db.user.update({'addr.country':"China"},{"$pull":{
        "hobbies":"read"}
    },
    {
        "multi":true
    }
    )
    View Code

      避免重复添加:$addToSet:

    #避免添加重复:"$addToSet"
    
    db.urls.insert({"_id":1,"urls":[]})
    
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    db.urls.update({"_id":1},{"$addToSet":{"urls":'http://www.baidu.com'}})
    
    db.urls.update({"_id":1},{
        "$addToSet":{
            "urls":{
            "$each":[
                'http://www.baidu.com',
                'http://www.baidu.com',
                'http://www.xxxx.com'
                ]
                }
            }
        }
    )
    View Code

      其他修改方法:

    #1、了解:限制大小"$slice",只留最后n个
    
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-2
        }
        }
    })
    
    #2、了解:排序The $sort element value must be either 1 or -1"
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-1,
            "$sort":-1
        }
        }
    })
    
    #注意:不能只将"$slice"或者"$sort"与"$push"配合使用,且必须使用"$eah"
    View Code

    六 可视化工具

    链接:https://robomongo.org/

    七 pymongo模块

    官网:http://api.mongodb.com/python/current/tutorial.html

    from pymongo import MongoClient
    
    #1、链接
    client=MongoClient('mongodb://root:123@localhost:27017/')
    # client = MongoClient('localhost', 27017)
    
    #2use 数据库
    db=client['db2'] #等同于:client.db1
    
    #3、查看库下所有的集合
    print(db.collection_names(include_system_collections=False))
    
    #4、创建集合
    table_user=db['userinfo'] #等同于:db.user
    
    #5、插入文档
    import datetime
    user0={
        "_id":1,
        "name":"egon",
        "birth":datetime.datetime.now(),
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'BJ'
        }
    }
    
    user1={
        "_id":2,
        "name":"alex",
        "birth":datetime.datetime.now(),
        "age":10,
        'hobbies':['music','read','dancing'],
        'addr':{
            'country':'China',
            'city':'weifang'
        }
    }
    # res=table_user.insert_many([user0,user1]).inserted_ids
    # print(res)
    # print(table_user.count())
    
    #6、查找
    
    # from pprint import pprint#格式化细
    # pprint(table_user.find_one())
    # for item in table_user.find():
    #     pprint(item)
    
    # print(table_user.find_one({"_id":{"$gte":1},"name":'egon'}))
    
    #7、更新
    table_user.update({'_id':1},{'name':'EGON'})
    
    #8、传入新的文档替换旧的文档
    table_user.save(
        {
            "_id":2,
            "name":'egon_xxx'
        }
    )
    View Code
  • 相关阅读:
    AndroidStudio项目CMakeLists解析
    Xposed那些事儿 — xposed框架的检测和反制
    从谷歌官网下载android 6.0源码、编译并刷入nexus 6p手机
    编译Xposed
    常用的delphi 第三方控件
    delphi安装控件
    delphi控件安装与删除
    从今天开始,每天都要写博客,加油
    关于ArrayAdapter的getCount()的方法会造成空指针异常的分析
    实现ListView的加载更多的效果,如何将按钮布局到始终在ListView的最后一行
  • 原文地址:https://www.cnblogs.com/fangjie0410/p/8288973.html
Copyright © 2011-2022 走看看