zoukankan      html  css  js  c++  java
  • Mongodb基础命令与用法

    Mongodb基础命令与用法

    查看版本号

    [root@VM_0_12_centos bin]# ./mongo -version
    MongoDB shell version v3.6.5
    git version: a20ecd3e3a174162052ff99913bc2ca9a839d618
    OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
    allocator: tcmalloc
    modules: none
    build environment:
        distmod: rhel70
        distarch: x86_64
        target_arch: x86_64
    查看
    show dbs; 查看数据库,查看库占用空间
     
    查找
    db.tablename.find()  查找所有
    使用
    use databaseName 选库
     
    show tables/collections 显示表
    注意 system开头的表不要动
    admin和Local这两个自带的库不要动
    show databases; 个别版本可以使用
     
    db.help(); 查看帮助
    创建
    mongodb是隐式创建数据库,直接use就能创建一个不存在的数据库。
    use newdbName;
     
    表也可以隐式创建。
    db.goods.insert({_id:1,name:'NOKIAn86',price:29.9})
     
    db.createCollection('user');  创建user表
    插入
    db.user.insert({name:'zhangsan',age:22});   插入数据
     
    db.user.find();   查看user表数据,会查到一个主键,_id,也是主键,自动生成的
     
    db.user.insert({_id:2,name:'poly',age:23});  指定主键的插入方式
     
    mongodb可以插入格式不一样的文档格式
    例如:
    db.user.insert({_id:3,name:'hmm',hobby:['basketball','football'],intro:{'title':'my intro','content':'from china'}})
    以上这种格式和之前的格式并不冲突,没有结构的特点。
     
    删除
    db.user.drop();  删除表
     
    db.dropDatabase(); 删除库
     
     
     
    增删改查:
    需要传一个json对象。
     
     
     
     
    修改:
    语法:
    db.collection.update(查询表达式,新值,选项)
    db.table.update(匹配条件,新文档,true(upsert),true(修改多个值))
    例:
    db.news.update({name:'QQ'},{name:'MSN'});
    查找news表中name值为QQ的文档,并将值改为msn,注意:这是替换,其他的值也会不见。
     
    如果只想修改某一列,用$set关键字
    db.collectionName.update(query,{$set:{name:'QQ'}})
    $set 修改某列的值
    $unset 删除某个列
    $rename 重命名某个列
    $inc 增长某个列
    $setOnInsert 当upsert为true时,并发生了Isnert操作时,可以补充的字段。
     
     

    在mongodb的命令交互界面中可以执行以下命令:
    db   查看目前指向的数据库
     
    还可以执行数学计算
    x = 200
    x / 5 ;
     
    可以使用JavaScript标准库
    Math.sin(Math.PI / 2);
     
    new Date("2010/1/1");
     
    "Hello,World".replace("World","Mongodb");
     

    新建表
    > post={"title":"My Blog Post","content":"Here's my blog post.","date":new Date()}
    {
        "title" : "My Blog Post",
        "content" : "Here's my blog post.",
        "date" : ISODate("2018-07-06T02:35:57.716Z")
    }
    > db.blog.insert(post)
    WriteResult({ "nInserted" : 1 })
    > show collections;
    blog
    fuzzing_agent.configuration
    system.users
    system.version
     
    定义一个字典
    然后db.表名.insert(变量)
     
    只查看一个文档:
    findOne()
    > db.blog.findOne();
    {
        "_id" : ObjectId("5b3ed5c1de8e397067390e0d"),
        "title" : "My Blog Post",
        "content" : "Here's my blog post.",
        "date" : ISODate("2018-07-06T02:35:57.716Z")
    }
     
    find命令一次最多显示20个匹配的文档。
     
     
    update
    update需要两个参数,第一个是限定条件(老文档,被替换的),第二个是新的文档。
    [ ]
    > db.blog.update({title:"My Blog Post"},post)
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blog.find()
    { "_id" : ObjectId("5b3ed5c1de8e397067390e0d"), "title" : "My Blog Post", "content" : "Here's my blog post.", "date" : ISODate("2018-07-06T02:35:57.716Z"), "comments" : [ ] }
    >
     
     
    删除
    remove
    db.blog.remove({title:"My Blog Post"})
     
    修改
    $set
    需要用$修改器,如果不用,直接update({目标文档},{新文档}),会将原来的文档直接替换。
    db.tester.update({"baz":0},{"$set":{"favorite book":"war and peace"}})
    如果{"baz":0}这个字段中没有"favorite book"这个字段,则添加;有则修改
     
    修改内嵌文档
    例:
    > db.blog.findOne();
    {
        "_id" : ObjectId("5b431029f9cc01fb9708024b"),
        "title" : "A Blog Post",
        "content" : "...",
        "author" : {
            "name" : "joe",
            "email" : "joe@example.com"
        }
    }
    > db.blog.update({"author.name":"joe"},{"$set":{"author.name":"michel"}})
    > db.blog.findOne();
    {
        "_id" : ObjectId("5b431029f9cc01fb9708024b"),
        "title" : "A Blog Post",
        "content" : "...",
        "author" : {
            "name" : "michel",
            "email" : "joe@example.com"
        }
    }
     
    $inc增加某个键的数字值
    例:
    > db.games.findOne();
    {
        "_id" : ObjectId("5b431235f9cc01fb9708024c"),
        "game" : "pinball",
        "user" : "tom"
    }
    > db.games.update({"user":"tom"},{"$inc":{"score":50}})             #没有则新建
    注意,$inc必须是数字格式,用于整型,长整型,双精度浮点型,不能用于null,布尔型,数字构成的字符串
    > db.games.findOne();
    {
        "_id" : ObjectId("5b431235f9cc01fb9708024c"),
        "game" : "pinball",
        "user" : "tom",
        "score" : 50
    }
    $inc的用处如下:
    > db.games.update({"user":"tom"},{"$inc":{"score":1000}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.games.findOne();
    {
        "_id" : ObjectId("5b431235f9cc01fb9708024c"),
        "game" : "pinball",
        "user" : "tom",
        "score" : 1050
    }
    会将score这个值在原有50的基础上增加1000,改为1050
     
    $push,向某个数组中添加元素
    例:
    > db.blog.findOne({"title":"A blog post"});
    {
        "_id" : ObjectId("5b431538f9cc01fb9708024d"),
        "title" : "A blog post",
        "content" : "...",
        "commnet" : [
            {
                "name" : "joe",
                "email" : "joe@example.com",
                "content" : "nice post"
            }
        ]
    }
    之前没有commnet这个键值对,通过
    > db.blog.update({"title" : "A blog post", "content" : "..."},{"$push":{"commnet":{"name":"joe","email":"joe@example.com","content":"nice post"}}})
    增加,会生成commnet:[]这个格式。
    在原有基础上,向commnet这个集合中添加内容:
    > db.blog.update({"title":"A blog post"},{"$push":{"commnet":{"name":"michel","email":"michel@example.com","content":"good job"}}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.blog.findOne({"title":"A blog post"});
    {
        "_id" : ObjectId("5b431538f9cc01fb9708024d"),
        "title" : "A blog post",
        "content" : "...",
        "commnet" : [
            {
                "name" : "joe",
                "email" : "joe@example.com",
                "content" : "nice post"
            },
            {
                "name" : "michel",
                "email" : "michel@example.com",
                "content" : "good job"
            }
        ]
    }
    列表中的多了一个文档。
     
    其他:
    $each  可以通过一次push添加多个值
    $slice slice必须是负数,限制包含最后加入的slice个数,比如-10,就会只保留最后添加的10个数,如果不够10个则全保留。
    $sort 排序
    注意,不能只将slice或sort与push配合使用,必须使用$each
     
    $addToSet,可以避免添加重复内容:
    db.users.update({"_id":ObjectId("123")},{"$addToSet":{"emails":"joe@gamil.com"}})
    如上,添加joe@gamil的时候,会检查是否已经存在,如果已经存在则不变,不存在则添加
     
    一次添加多个邮件地址,并去重:
    db.users.update({"_id":ObjectId("123")},{"$addToSet":{"emails":{"$each":["joe@php.net","joe@example.com","joe@python.org"]}}})
     
     
    $ne也是避免添加重复内容,在查找条件中写,效果不如addToSet
     
     
    基于位置的数组修改器
    通过数组的下标找到对应元素,下标从0开始。
    db.blog.update({"post":"post_id"},{"$inc":{"comments.0.vates":1}})
    如上,找到comments集合中下标为0的元素,将其vates+1
     
    如果不知道下标位置,但知道需要更改的内容,可以通过一下方法修改:
    db.blog.update({"comments.author":"John"},{"$set":{"comments.$.author":"jim"}})
    如上,将已经匹配的John修改为jim,不知道下标则写$
     
     
    修改器的速度
    有的修改器速度比较快,如$inc,可以就地更改,不需要修改文档的大小,只需要改值。
    有的会修改文档的大小,速度就会慢一些,$set能在文档大小不发生变化时立即修改,否则性能也会下降。
     
    文档在插入Mongodb的时候,依次插入的文档会在磁盘上的位置是相邻的,因此如果一个文档变大了,原先的位置放不下了,这个文档就会被移动到集合的另一个位置。
    比如
    {"x":"a"}
    {"x":"b"}
    {"x":"c"}
    将x:b改为x:bbbbbb
    结果是
    {"x":"a"}
    {"x":"c"}
    {"x":"bbbbb"}
     
    填充因子
    db.tablename.stats()
    原理:
    填充因子是Mongodb为每个新文档预留的增长空间,如果一个文档增大之后,填充因子会随之增加,当初没有多余空间的时候,文档会移动位置,然后之前的位置被填充因子覆盖,填充因子变大之后,所有的空间都会增加
    到填充因子的大小,直到文档不在继续变大,之后,填充因子会缓慢变小。
    填充因子的大小无法手动设置。
     
    upsert
    特殊的更新机制,如果没找到符合更新条件的文档,就会以这个条件和更新文档为基础,创建一个新的文档。
    传统的修改方式:
    js
    > blog=db.analytics.findOne({"url":"/blog"})   #判断是否有这个文档
    null
    > if (blog){blog.pageviews++;db.analytics.save(blog);} else{db.analytics.save({"url":"/blog",pageviews:1})}    #如果有则+1,没有则保存
    WriteResult({ "nInserted" : 1 })
    > show tables;
    analytics
    blog
    games
    list
    tester
    > db.analytics.find();
    { "_id" : ObjectId("5b432c34f9cc01fb9708024f"), "url" : "/blog", "pageviews" : 1 }
    >
    使用upsert,既可以避免竞态问题,又可以缩减代码量,
    第三个参数表示这个是upsert
    db.analytics.update({"url":"/blog"},{"$inc":{"pageviews":1}},true)
    作用和上面的一样,但是更高效,并且是原子性。
     
    > db.users.update({"rep":25},{"$inc":{"rep":3}},true)
    WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("5b432dc2764f0dcf8c8302cf")
    })
    如上,upsert创建一个rep值为25的文档,随后将这个值+3,最后得到28.
    如果不加这个true,也就是不用upsert,update则匹配不到这个rep:25,然后就不会对集合进行任何更新。
    如果再执行这条代码。则会在次创建一个文档,因为没有匹配到rep:25,唯一一个文档是rep:28
     
     
     
    $setOnInsert
    创建文档的同时并为他赋值,但是在之后的所有更新操作中,这个字段的值不在改变。
    例:
    > db.time.update({},{"$setOnInsert":{"createdAt":new Date()}},true)
    WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("5b432f81764f0dcf8c8302dc")
    })
    > db.time.find();
    { "_id" : ObjectId("5b432f81764f0dcf8c8302dc"), "createdAt" : ISODate("2018-07-09T09:48:48.986Z") }
    > db.time.update({},{"$setOnInsert":{"createdAt":new Date()}},true)
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
    > db.time.find();
    { "_id" : ObjectId("5b432f81764f0dcf8c8302dc"), "createdAt" : ISODate("2018-07-09T09:48:48.986Z") }
    >
    再次运行这个更新,会匹配到这个文档已存在,所以不会再插入文档,因此createdAt的值也不会改变。
     
    同时更新多个文档
    默认情况,更新只针对第一个匹配的文档执行操作,要是需要有多个文档符合条件并被更新,需要将Update的第四个参数设置为true。
    > db.users.find();
    { "_id" : ObjectId("5b44117cf9cc01fb97080252"), "name" : "tom", "birthday" : "10/13/1991" }
    { "_id" : ObjectId("5b441194f9cc01fb97080253"), "name" : "jerry", "birthday" : "05/24/1993" }
    { "_id" : ObjectId("5b4411a6f9cc01fb97080254"), "name" : "mike", "birthday" : "10/13/1991" }
    { "_id" : ObjectId("5b4411bff9cc01fb97080255"), "name" : "michel", "birthday" : "03/14/1989" }
    { "_id" : ObjectId("5b4411d0f9cc01fb97080256"), "name" : "lucy", "birthday" : "10/13/1991" }
    > db.users.update({"birthday":"10/13/1991"},{"$set":{"gift":"happy birthday!!!"}},false,true)
    WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
    > db.users.find();
    { "_id" : ObjectId("5b44117cf9cc01fb97080252"), "name" : "tom", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }
    { "_id" : ObjectId("5b441194f9cc01fb97080253"), "name" : "jerry", "birthday" : "05/24/1993" }
    { "_id" : ObjectId("5b4411a6f9cc01fb97080254"), "name" : "mike", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }
    { "_id" : ObjectId("5b4411bff9cc01fb97080255"), "name" : "michel", "birthday" : "03/14/1989" }
    { "_id" : ObjectId("5b4411d0f9cc01fb97080256"), "name" : "lucy", "birthday" : "10/13/1991", "gift" : "happy birthday!!!" }
    如上,给users表生日为10/13/1991的人一个gift,效果如上。
     
     
     
     
     
     
    删除
    删除某个键
    db.tester.update({"baz":1},{"$unset":{"favorite book":"Ender's Game"}})
    删除baz:1这个条目的favorite book字典
     
     
    删除数组中的元素
    $pop
    把数组看成队列,可以用$pop
    {"$pop":{"key":1}} 从数组最后一个元素删除
    {"$pop":{"key":-1}} 从数组第一个元素删除
     
    $pull
    根据条件删除数组元素
    > db.list.insert({"todo":["dishes","laundry","dry cleaning"]})
    WriteResult({ "nInserted" : 1 })
    > db.list.find();
    { "_id" : ObjectId("5b431e50f9cc01fb9708024e"), "todo" : [ "dishes", "laundry", "dry cleaning" ] }
    > db.list.update({},{"$pull":{"todo":"laundry"}})
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.list.find();
    { "_id" : ObjectId("5b431e50f9cc01fb9708024e"), "todo" : [ "dishes", "dry cleaning" ] }
    如上,删除了laundry
    $pull会将所有匹配的文档删除,而不是只删除一个,对数组[1,1,2,1]执行Pull 1 则结果只剩2.
    数组操作符只能用于包含数组值得键,例如,不能将一个整数插入数组,也不能将一个字符串从数组中弹出,要修改标量值,需要$set和$inc。
     
     
     
    getLastError
    检查最后一次操作中的错误。编写脚本的时候可能会用到。
    db.runCommand({getLastError:1})
     
    findAndModify
    更新文档并返回被更新的文档
    db.runCommand({"findAndModify":"processes","query":{"status":"READY"},"sort":{"priority":-1},"update":{"$set":{"status":"RUNNING"}}})
     
    findAndModify的其他字段
    query 查询文档,用于检索文档的条件
    sort  排序结果的条件
    update 修改文档,用于对匹配的文档进行更新
    remove 布尔类型,表示是否删除文档
    new 布尔类型,表示返回更新前还是更新后的文档,默认是更新前的文档
    fields 文档中需要返回的字段
    upsert   布尔类型,值为true表示upsert,默认为false
     
     
    查询
    查询条件
     
    db.table.find(匹配条件,指定返回内容)
     
    db.users.find({"name":"tom","age":27})    两个查询条件,条件1 and 条件2
    指定返回内容
    通过find或findOne的第二个参数来指定想要返回的键
    db.users.find({},{"username":1,"email":1})
    默认情况下,_id这个键是被返回的。
    不希望返回_id的做法:
    db.users.find({},{"username":1,"id":0})
    如上返回了username,但是没有返回id
     
    $lt =  '<'
    $lte = '<='
    $gt = '>'
    $gte ='>='
    $ne  不等于 <>
     
     
    例:
    db.users.find({"age":{"$gte":18,"$lte":30}})
    如上查找大于等于18 and小于等于30的人
    注意:
    {"x":5}
    {"x":15}
    {"x":25}
    {"x":[5,25]}
    >db.test.find({"x":{"$gt":10,"$lt":20}})
    {"x":15}
    {"x":[5,25]}
    如上,之所以会返回[5,25] 是因为25大于等于10,所以也一同返回了,
    db.test.find({"x":{"$elemMatch":{"$gt":10,"$lt":20}}})
    $elemMatch可以同时查询条件中两个语句与一个数组元素做比较,但是$elemMatch不会匹配非数组元素,所以在这里找不到任何匹配内容。
    如果当前字段创建过索引,可以使用min()和max()将查询条件遍历的索引范围限制为$gt和$lt的值
    >db.test.find({"x":{"$gt":10,"$lt":20}}).min({"x":10}).max({"x":20})
     
     
     
    这种方法对日期也同样有用
    例:
    start=new Date("01/01/2007")
    db.users.find({"registered":{"$lt":start}})
    如上,查找01/01/2007以前注册的人。
     
    $ne用法
    db.users.find("username":{"$ne":"joe"})
    查找名字不叫Joe的人
     
     
    OR查询
    $in
    $or
    $nin
    $not
     
     
     
     
    $in
    例:
    查找中奖号码是725,542,390的所有中奖文档。
    db.raffle.find({"ticket_no":{"$in":[725,542,390]}})
    例:
    超找需要同时匹配id和用户名
    db.users.find({"user_id":{"$in":[12345,"joe"]}})
    如上,会匹配user_id是12345的,也会匹配user_id是joe的
     
    $nin
    与$in相反
    例:
    找到所有没中奖的人
    db.raffle.find({"ticket_no":{"$nin":[725,542,390]}})
     
    $or
    例:
    找到中奖的人
    db.raffle.find({"$or":[{"ticket_no":725},{"winner":true}]})
    如上,找到ticket_no为725的或者有winner为true的人
     
    复杂一点的查找中奖人,结合$or和$in:
    db.raffle.find({"$or":[{"ticket_no":{"$in":[725,542,390]}},{"winner":true}]})
    如上,为查找ticket_no为725或542或390的,或者winner为true的人。
    $or可以同时使用不同的查询条件,而$in只能或同样类型的条件。
     
    $not
    db.users.find({"id_num":{"$not":{"$mod":[5,1]}}})
    如上$not为取反,$mod为取模
     
    null
    匹配null
    如果直接通过"z":null,会将其他键不是z但值是null的也匹配出来,所以需要写成以下方式:
    db.c.find({"z":{"$in":[null],"$exists":true}})
    如上,匹配z的值为null的同时判断是否存在。
     
    正则表达式
    匹配名字为Joe或者joe的用户
    db.users.find({"name":/joe/i})
     
    Mongodb使用PCRE正则表达式库来匹配正则,可以先用js检查一下语法。
     
     
    数组查询
    数组元素查询和普通查询是一样的。
    db.food.insert({"fruit":["apple","banana","peach"]})
    查询:
    db.food.find({"fruit":"banana"})
    也能找到该条数据,效果如下(不合法):
    {"fruit":"apple","fruit":"banana","furit":"peach"}
     
     
    $all
    匹配既有a也有b的,和and类似
    > db.food.find();
    { "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] }
    { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
     
    > db.food.find({"fruit":"apple","fruit":"banana"})
    { "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
    > db.food.find({"fruit":{"$all":["apple","banana"]}})  
    { "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
    如上第二个,是使用$all的写法,作用是匹配既有apple又有banana的情况。
    第一种是我自己想的方法,效果是一样的。
     
    $size
    根据指定列表长度,来筛选符合列表长度的文档。
    > db.food.find();
    { "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
    { "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] }
    { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
    { "_id" : 4, "fruit" : [ "orange", "blueberry" ] }
    > db.food.find({"fruit":{"$size":2}})
    { "_id" : 4, "fruit" : [ "orange", "blueberry" ] }
     
    $slice
    find的第二个参数是指定返回内容,配合$slice可以指定返回匹配数组元素的一个子集
    例如:
    db.blog.findOne(匹配条件,{"comments":{"$slice":10}})
    如上,查找博客评论前10条评论
    例如:
    db.blog.findOne(匹配条件,{"comments":{"$slice":-10}})
    如上,查找博客评论后10条评论
    例如:
    db.blog.findOne(匹配条件,{"comments":{"$slice":[23,10]}})
    如上,查找评论集合第24-33的元素,23是指跳过前23个元素,10是指取10个元素。
     
    注意,slice会默认返回除了指定子集的其他所有的键,比如_id,title什么的。
     
    例如:
    db.blog.find({"comments.name":"bob"},{"comments.$":1})
    如上查找评论名为bob的数组元素,并取第一个,如果bob评论了多条也只返回第一个。
     
    内嵌文档查询:
    > db.score.findOne()
    {
        "_id" : ObjectId("5b4468fef9cc01fb97080257"),
        "content" : "joe",
        "comments" : [
            {
                "author" : "joe",
                "score" : 3,
                "comment" : "nice post"
            },
            {
                "author" : "mary",
                "score" : 6,
                "comment" : "terrible post"
            }
        ]
    }
     
    查询mary分数在5分以上的评论
    > db.score.find({"comments":{"$elemMatch":{"author":"mary","score":{"$gte":5}}}})
    { "_id" : ObjectId("5b4468fef9cc01fb97080257"), "content" : "joe", "comments" : [ { "author" : "joe", "score" : 3, "comment" : "nice post" }, { "author" : "mary", "score" : 6, "comment" : "terrible post" } ] }
    $elemMatch将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到。
    内嵌文档不能使用如下查找方式:
    db.score.find({"comments":{"author":"mary","score":{"$gte":5}}})
    内嵌文档的匹配必须整个文档完全匹配,这个查询不会匹配comments键
    db.score.find({"comments.author":"mary","comments.score":{"$gte":5}})
    符合author条件的评论和符合score条件的评论可能不是一个评论。
    $where
    $where可以后面使用javascript语句,所以尽量限制用户使用$where方式查询。
    例子
    > db.fooo.find();
    { "_id" : ObjectId("5b446d78f9cc01fb97080258"), "apple" : 1, "banana" : 6, "speach" : 3 }
    { "_id" : ObjectId("5b446d92f9cc01fb97080259"), "apple" : 8, "spinach" : 4, "watermelon" : 4 }
     
     
    查找两个键具有相同值得文档,第二个文档中spinach和watermelon的值相同,所以应该返回它
    > db.fooo.find({"$where":function(){for (var current in this){ for (var other in this){if (current != other && this[current] == this [other]){return  true ;}}}return false;}});
    { "_id" : ObjectId("5b446d92f9cc01fb97080259"), "apple" : 8, "spinach" : 4, "watermelon" : 4 }
    >
    $where查询比常规查询慢很多,而且有一定危险,所以尽量不用。
    每个文档都要从BSON转换成JavaScript对象,然后通过$where表达式运行,而且$where不能使用索引。 
     
    limit
    >db.c.find().limit(3)
    如上,限制返回结果为前三条
     
    skip
    db.c.find().skip(3)
    如上,跳过前三条结果,如果集合里不足3条则不予显示
     
    sort
    db.stock.find().sort({username:1,age:-1})
    如上,按照username升序及age降序排序
    1为升序,-1为降序
     
    组合使用:
    db.stock.find({"desc":"mp3"}).limit(50).sort("price":-1)
    如上,可以作为在线商店的分页使用,返回Mp3内容前50条,并按价格从高到低排序。
    点击下一页后:
    db.stock.find({"desc":"mp3"}).limit(50).skip(50).sort("price":-1)
     
    注意,跳过过多会导致性能问题。
    注意,不同类型的优先级:
    默认如下:
    1 最小值
    2 null
    3 数字
    4 字符串
    5 对象/文档
    6 数组
    7 二进制数据
    8 对象ID
    9 布尔型
    10 日期
    11 时间戳
    12 正则表达式
    13 最大值
     
     
    索引
    创建索引
    > db.users.ensureIndex({"name":1})
    {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
    }
    如上,给username字段创建索引。
    db.currentOp() 可以查看状态。
    因为创建索引是有代价的,在插入更新删除的时候都要更耗费时间,还要更新集合所有的索引。所以Mongodb限制每个集合最多只能有64个索引。
    通常在一个特定的集合上,不应该拥有2个以上的索引。
     
    创建复合索引
    db.users.ensureIndex({"age":1,"username":1})
    复合索引在查询中有多个键,或者查询中有多个排序方向作用比较大。
     
    索引嵌套文档
    {
    "username":"sid",
    "loc":{
        "ip":"1.2.3.4",
        "city":"Springfield",
        "state":"NY"
        }
    }
    db.users.ensureIndex({"loc.city":1})
    如上,给city字段建立索引,提高这个字段的查询速度。
    注意:给内嵌文档创建索引和给内嵌文档的字段创建索引是不同的,除非查找整个内嵌文档,不然查找内嵌文档的某个字段的时候,内嵌文档的索引是没有作用的,需要建立字段索引。
     
    数组索引
    给数组创建索引相当于给数组中所有的元素创建索引,这样对数组的更改会比较耗时。
     
    唯一索引
    db.users.ensureIndex({"username":1},{"unique":true})
    如上,给username设置了唯一索引,如果你插入两个同名的人就会报错。
    _id也是唯一索引,区别是_id不能被删除,而其他唯一索引可以被删除。
     
    强制唯一索引
    在创建唯一索引的时候有时候会失败,因为已有的数据可能会有重复,但由于数据过多又不知道哪些数据重复,这个时候可以使用
    dropDups
    db.people.ensureIndex({"username":1},{"unique":true,"dropDups":true})
    dropDups会强制删除重复的文档。慎用
     
     
     
    查询计划
    如果被查询的字段有多个索引,mongodb会从这个字段的索引子集中为每次查询计划选择一个,这些查询计划是并行执行的,最早返回100个结果的就会保留,其他的计划被终止。
    查询计划会被缓存,这个查询以后会使用这条计划直到集合数据发生了比较大的变动。建立索引时或每执行1000次查询之后,查询优化器都会重新评估查询计划。
     
    何时不应该使用索引
    当数据比较少的时候,不使用索引反而比有索引快,因为使用索引需要先去索引表查找,再根据指针去数据表查找,需要找两次。
     
    所有的索引都保存在system.index集合中,只能通过ensureIndex或者dropIndexes对其进行操作。
    可以通过db.tablename.getIndexes()来查看这个表所有索引信息。
     
    删除索引
    db.people.dropIndex("x_1_y_1")
    用索引描述信息里name字段的值来指定需要删除的索引。
     
     
     
     

     
    数据类型
    null
    {"x":null}
     
    布尔型
    {"x":true}
     
    数值
    默认64位浮点数
    {"x":3.14}
    {"x":3}
     
    整型
    NumberInt表示4字节带符号整数
    NumberLong表示8字符带符号整数
    {"x":NumberInt("3")}
    {"x":NumberLong("3")}
     
    字符串
    UTF-8字符串
    {"x":"foobar"}
     
    日期
    毫秒数,不存储时区
    {"x":new Date()}
     
    正则表达式
    使用正则表达式作为限定条件
    {"x":/foorbar/i}
     
    数组
    {"x":["a","b","c"]}
     
    内嵌文档
    {"x":{"foo":"bar"}}
     
    对象id
    {"x":ObjectId()}
     
    代码
    {"x":function() {/*...*/}}
     
     
     
    插入校验
    所有文档都必须小于16MB。
     
     
    批量插入脚本
    for (var i=0 ;i<100; i++) {db.tester.insert({"foo":"bar","baz":i,"z":10-i})}
     
     

     
    固定集合
    固定集合相当于一个队列,如果固定集合已经满了,如果再向固定集合中添加内容,那么最老的文档会被删除。
    固定集合不能被分片。
    固定集合可以用于记录日志。
    固定集合必须在使用之前显式创建。
    db.createCollection("my_collection",{"capped":true,"size":100000})
    如上方式创建固定集合,创建的固定集合叫my_collection,大小为100000字节,除了大小,固定集合还可以指定固定集合中文档的数量。
    > db.createCollection("my_collection2",{"capped":true,"size":100000,"max":100});
    { "ok" : 1 }
    固定集合创建之后就不能改变了。如果需要修改只能删除之后再重建。
     
    创建固定集合的另一种方式,可以将常规集合转为固定集合。
    db.runCommand({"convertToCapped":"test","size":10000})
    test为集合名字。
    无法将固定集合转为常规集合。只能删除重建。
     
    自然排序
    对于固定集合来说,自然排序就是从旧到新排序,也可以按照从新到旧排序。是按照文档的插入顺序排列的。
    db.my_collection.find().sort({"$natural":-1})
     
     
     
     
     
    创建没有_id索引的集合
    如果在调用createCollection创建集合时指定autoIndexId选项为false,创建的集合就不会自动在_id上创建索引
    一般不这么用,但是如果对只有插入操作的集合来说,效率会提升一些。
     
     
    TTL索引
    (time-to-live index)具有生命周期的索引。
    这种索引允许为每一个文档设置一个超时时间,一个文档到达预期设置的超时时间后会被删除。这种类型的索引对于缓存问题非常有帮助。
    db.foo.ensureIndex({"lastUpdated":1},{"expireAfterSecs":60*60*24})
    如上,给lastUpdated字段建立了TTL索引,当服务器比对发现文件lastUpdated字段的时间晚expireAfterSecs秒时,文档就会被删除。
     
    mongodb每分钟会对TTL索引进行一次清理。
     
     
     
    聚合框架
    用于对一连串的文档进行处理
    包括:
    管道(pipeline)
    筛选(filtering)
    投射(projecting)
    分组(grouping)
    排序(sorting)
    限制(limiting)
    跳过(skipping)
     
    例如
    找到发表文章最多的前五个作者
    db.articles.aggregate({"$project":{"author":1}},{"$group":{"_id":"$author","count":{"$sum":1}}},{"$sort":{"count":-1}},{"$limit":5})
    1 将每个文章中的作者投射出来
    2 将作者按照名字排序,统计每个名字出现的次数
            指定需要分组的字段author,这个操作完成后,每个作者只对应一个文档结果
    3 将作者按照名字出现次数降序排列
    4 将返回结果限制为前五个
     
    aggregate()会返回一个文档数组。
     
     
    $match
    用于对文档集合进行筛选,筛选之后可以再对文档子集做聚合。
    $match可以使用所有常规的查询操作符($gt,$lt$in等)
    通常尽可能将$match放在管道的前面位置,好处1是可以快速将不需要的文档过滤掉,2是在投射分组之前执行match可以使用索引。
     
    $project
    使用$project可以从子文档中提取字段,可以重命名字段等等。
    db.articles.aggregate({"$project":{"author":1,"_id":0}})
    如上,可以只返回author字段内容,却不返回_id
     
    将投射过的字段重命名
    db.users.aggregate({"$project":{"userId":"$_id","_id":0}})
    如上,将_id重命名为userId
    注意需要将_id:0,不然这个字段会返回,也就是相当于返回两次,一个被重命名为userId
     
     
    数学表达式
    可以对数值做操作。
    db.employees.aggregate({"$project":{"totalPay":{"$add":["$salary","$bonus"]}}})
    如上,是将salary和bonus字段相加。
     
    db.employees.aggregate({"$project":{"totalPay":{"$subtract":[{"$add":["$salary","$bonus"]},"$401k"]}}})
    如上,是用salary+bonus-401k
     
    操作符语法
    "$add":[expr1,expr2]
    这个操作符接收一个或多个表达式作为参数,将这些表达式相加。
     
    "$subtract":[expr1,expr2]
    接受两个参数,用第一个参数减去第二个参数作为结果。
     
     
    "$multiply":[expr1,expr2...]
    接收一个或多个表达式,将其相乘。
     
    "$divide":[expr1,expr2]
    接收两个表达式,用第一个表达式除以第二个表达式的商作为结果。
     
    "$mod":[expr1,expr2]
    接收两个表达式,将第一个表达式除以第二个表达式得到的余数作为结果。
     
     
    日期表达式
    $year
    $month
    $week
    $dayOfMonth
    $dayOfWeek
    $dayOfYear
    $hour
    $minute
    $second
     
    只能对日期做操作,不能对数字做操作。
     
     
    字符串表达式
    "$substr":[expr,startOffset,numToReturn]
    expr必须是字符串,startOffset字节开始到numToReturn字节。
     
    "$concat":[expr1,expr2..]
    将给定的字符串连接在一起作为结果返回。
     
    "$toLower":expr
    参数expr必须是个字符串,这个操作返回expr小写
     
     
    "$toUpper":expr
    参数expr必须是个字符串,这个操作返回expr大写
     
    例如
    db.employees.aggregate({"$project":{"email":{"$concat":[{"$substr":["$firstName",0,1]},".","$lastName","@example.com"]}}})
    生成j.doe@example.com格式的例子。
     
     
    逻辑表达式
    "$cmp":[expr1,expr2]
    如果expr1=expr2,返回0,如果expr1<2返回一个负数,如果expr1>expr2,返回一个正数
     
    "$strcasecmp":[string1,string2]
    比较string1和string2,区分大小写,只对罗马字符组成的字符串有效。
     
    "$eq"/"$ne"/"$gt"/"$gte"/"$lt"/"$lte"
     
    "$and"
    "$or"  或
    "$not"  取反
     
    控制语句
    "$cond":[booleanExpr,trueExpr,falseExpr]
    如果booleanExpr为true,返回trueExpr,否则返回falseExpr
     
    "$ifNull":[expr,replacementExpr]
    如果expr是null,返回replacementExpr,否则返回expr。
  • 相关阅读:
    实验12——java取整、猜数和猜拳
    实验11——java线程模拟卖票
    实验10—— java读取歌词文件内容动画输出
    实验09——java基于TCP实现客户端与服务端通信
    JavaSE第十四天
    javaSE第十一天
    JavaSE第十天
    JavaSE第十天
    JavaSE第九天
    JavaSE第八天
  • 原文地址:https://www.cnblogs.com/ArmoredTitan/p/9309680.html
Copyright © 2011-2022 走看看