文章转自:http://ls-la.me/2015/07/24/mongo-02/
这一节来看看MongoDB的CURD操作。启动mongod之后,用./bin/mongo
进入交互命令行:
$ ./bin/mongo MongoDB shell version: 3.0 .4 connecting to: test > help db.help() help on db methods db.mycoll.help() help on collection methods sh.help() sharding helpers rs.help() replica set helpers help admin administrative help help connect connecting to a db help help keys key shortcuts help misc misc things to know help mr mapreduce show dbs show database names show collections show collections in current database show users show users in current database show profile show most recent system.profile entries with time >= 1 ms show logs show the accessible logger names show log [name] prints out the last segment of log in memory, 'global' is default use <db_name> set current database db.foo.find() list objects in collection foo db.foo.find( { a : 1 } ) list objects in foo where a == 1 it result of the last line evaluated; use to further iterate DBQuery.shellBatchSize = x set default number of items to display on shell exit quit the mongo shell
对db的操作
db.listCommands() db.serverStatus() show dbs use nisnaker show collections db.stats() db.dropDatabase() db.cloneCollection() db.cloneDatabase() db.copyDatabase() db.currentOp() db.killOp(opid) db.getLastError() db.getMongo() db.getName() db.hostInfo() db.isMaster() db.repairDatabase() db.serverBuildInfo() db.serverStatus() db.shutdownServer()
对集合的操作
db.createCollection('colA' ) db.colA.drop() db.colA.copyTo('colB' ) db.colA.renamCollection('colAA' ) db.colA.stats() db.colA.dataSize() db.colA.storageSize() db.colA.totalSize() db.colA.totalIndexSize()
对数据的操作(CURD)
插入
插入就用一个函数:insert
,唯一的参数就是要插入的对象。由于mongo的数据模型比sql要灵活,能直接插入一个json对象,所以这里没办法转为对应的sql语句。
> db.colA.insert({ a: 1 , b: 'stringB' , c: ['arrayC1' , 'arrayC2' ], d: { d1: 'stringD1' , d2: ['arrayD21' , 'arrayD22' ], d3: {} } });
批量插入数据,其实就是插入一个对象数组:
> db.colA.insert([ {'book' : 'book A' , page: 100 , readers: ['zhangsan' , 'lisi' ]}, {'book' : 'book B' , page: 200 , readers: []} ]);
对于同一个集合,理论上可以插入不同格式的数据,不过建议分集合管理,有利于提高查询效率。
删除
删除也比较简单,两个参数:
query
查询条件。这个query和mysql的where一样复杂,我们放在查询里边去说。justOne
默认为false,true的时候在符合条件的数据中,只删除一条。
db.colA.remove({ b: 'stringB' })
注意:remove
的参数不能为空,如果要清空数据,直接删除集合就行,或者db.colA.remove({})
。
更新
update
update(<query>, <update>, {<upsert>, <multi>})
有三个参数:
query
是查询条件,这个一会再说,先重点说udpate
。update
是更新数据内容,相当于set
的作用。upsert
默认是false,如果设置为true,会在query
没有找到数据的情况下,把update
插入集合。multi
默认是false,如果集合中有多条数据符合query
条件,只更新其中一条。设为true会全部更新。
> db.colA.update( {book: 'book A' }, {book: 'book AAA' } ) > db.colA.find() { "_id" : ObjectId("55b20e86d48beedae8d8726e" ), "book" : "book AAA" , "readers" : [ "zhangsan" , "lisi" ] } { "_id" : ObjectId("55b20e86d48beedae8d8726f" ), "book" : "book B" , "page" : 200 , "readers" : [ ] } > db.colA.update( {book: 'book A' }, { $set: {book: 'book AAA' , cover: '01.png' }, $inc: {page: 1 } }, {multi: true , upsert: false } ) > db.colA.find() { "_id" : ObjectId("55b20e86d48beedae8d8726e" ), "book" : "book AAA" , "page" : 101 , "readers" : [ "zhangsan" , "lisi" ], "cover" : "01.png" } { "_id" : ObjectId("55b20e86d48beedae8d8726f" ), "book" : "book B" , "page" : 200 , "readers" : [ ] }
$set
和$inc
都是更新操作的时候经常用到的关键字,下边是所有关键字(这一块的文档在:http://docs.mongodb.org/manual/reference/operator/update/ ):
字段相关: `$inc ` 增加,需要减少把值设为负数就行。不存在则插入,`$inc : {k1: 1 , k2: -1 }`。 `$mul ` 扩大倍数。 `$mul : {k1: 2 , k2: 0.5 }`。 `$rename ` 重命名字段,`$rename : {k1: K1, k2: K2}`。 `$setOnInsert ` 顾名思义,如果是在插入数据的情况下才设置,也就是需要`upsert`设置为true 。`$setOnInsert : {k: v}`。 `$set ` 更新键,不存在则插入。`$set : {k1: v1, k2: v2}`。 `$unset ` 删除键,`$unset : {k1: 1 , k2: 1 }`。 `$min ` 当指定的值小于字段的原始值时,就把字段设置为新值,否则不作修改。`$min : {k1: v1}`,简单说就是 `new_value = min(old_value, v1)` `$max ` 与`$min `相反,`new_value = max(v1, old_value)` `$currentDate ` 将某字段设置为当前时间,`$currentDate : {d1: 'timestamp' , d2: 'date' , d3: true }`,'date' 和'true' 一样效果。 数组相关: `$` 不能和`upsert`参数一起使用,代指在query中出现过的数组,`update({ _id: 1 , grades: 80 }, { $set : { "grades.$" : 82 } })`,把80 更新为82 。 `$push ` 向数组中添加元素,比如一本书有了新读者:`$push : {readers: 'nisnaker' }` `$pop ` 移除元素,`$pop : {readers: 1 }`从队尾移除,`$pop : {readers: -1 }`从队首移除。 `$pull ` 从数组中移除指定元素:`$pull : {readers: 'nisnaker' }`,`$pull : {num : {$gte : 10 }}` `$pullAll ` 从数组中移除多个元素,$pullAll : {num: [3 , 9 ]} `$addToSet ` 向数组中添加新元素,`$pull `有可能把重复的元素推入数组,而`$addToSet `会做重复检查,`$addToSet : {readers: 'nisnaler' }`,由于reader中已经有nisnaker这个读者了,所以这一项操作不会引起任何改变。 `$isolated ` 更改数据时加锁,保持一致性。 修饰相关: `$each ` 修饰`$addToSet `和`$push `,把多个值推入数组,`$push : {num: {$each : [1 , 2 , 3 ]}}` `$slice ` 修饰`$push `,插入之后再截取,`$push : {num: {$each : [1 , 2 , 3 ], slice: -2 }}` => num: [2 , 3 ] `$sort ` 修饰`$push `,插入后排序,`$push : {dat: {$each : [{score: 2 }, {score: 1 }], sort: {score: 1 }}}` => [{score: 1 }, {score: 2 }],按score的升序排列,-1 是降序。 `$position ` 修饰`$push `,在数组的指定位置插入数据,`$push : {scores: {$each : [1 , 2 ], $position : 0 }}`,在开头插入数据。 按位操作: `$bit ` 按位操作,`$bit : {dat: {and: 10 }}`,`dat = dat & 10 `,可选选项[and, or, xor] 其实主要是要记录这个,按位,可以支持各种属性比较多的时候,直接设置一个长串~~~
save
只有一个参数:数据文档,db.colA.save({"_id": "someid", "data": "some data"})
。
如果文档中有_id
键,则跟update
的upsert
功能一样,如果集合中对应的_id
不存在,则直接插入;如果存在,就整体 更新文档。
如果文档中没有_id
,则直接插入,和insert
作用一样。
使用和insert
一样,如果文档中有_id
,则跟update
的upsert
查询
好了,现在来看看query,怎么从庞大复杂的数据中,拿到我们想要的。
> db.colA.find({book: "book B" }) { "_id" : ObjectId("55b213fcd48beedae8d87275" ), "book" : "book B" , "page" : 200 , "readers" : [ ] } > db.colA.find({book: 'book B' , page: {$gt: 150 }}, {book: 1 }) { "_id" : ObjectId("55b213fcd48beedae8d87275" ), "book" : "book B" } > db.colA.count({book: 'book B' , page: {$gt: 150 }}) 1
关键字
依然先来看一下关键字(文档: http://docs.mongodb.org/manual/reference/operator/query/ ):
比较相关: `$eq ` = `$gt ` > `$gte ` >= `$lt ` < `$lte ` <= `$ne ` != `$in ` 匹配数组,比如原数组`tags: ['red' , 'blue' ]`,现在有查询`{tags: {$in : ['red' , 'green' ]}}`,则匹配为true 。匹配规则为:原数组中至少有一个在查询数组中。这里也可以使用正则,如:`{tags: {$in : [/re/, /blu/]}}` `$nin ` 与`$in `相反,意为一个都不在,或者连字段都不存在。 需要注意的是,`$in `和`$nin `还可以筛选字段,比如在之前的例子中,选出页码是50 或者200 的书:`{page: {$in : [50 , 200 ]}}`。 逻辑相关: `$or ` 同SQL中的`or`,用法:`{$or : [{book: 'book A' }, {page: 200 }]}`,相当于`where book = 'book A' or page = 200 `。 `$and ` 同SQL中的`and`。用法:`{$and : [{book: 'book A' }, {page: 200 }]}`,相当于`where book = 'book A' and page = 200 `。 `$not ` 取反:`{page: {$not : {$eq : 100 }}}`,即`page != 100 `。支持正则:`{book: {$not : /^b/}}`。 `$nor ` 既不也不。`{$nor : [{page: 1000 }, {book: 'book Z' }]}`,相当于:`where page != 1000 and book != 'book Z' `。 字段相关: `$exists ` 字段存在:`{author: {$exists : true }}`,所有存在'作者' 这个字段的数据,即使字段值为null,也算存在。 `$type ` 字段类型:`{tags: {$type : 2 }}`,会找出`String`类型或者至少有一个字符串的`Array`类型。更多类型说明在这里: http://docs.mongodb.org/manual/reference/operator/query/type / 求值相关: `$mod ` 取模,`{page: {$mod : [4 , 3 ]}}`,找出除4 余数为3 的数据。 `$regex ` 正则,`{name: {$regex : /^test /i}}`。 `$text ` 文本搜索。这个比较复杂,详细文档在这里: http://docs.mongodb.org/manual/reference/operator/query/text/ `$where ` js表达式手写where 条件。比如找出页码大于100 的书: `db.colA.find({$where : "this.page > 150" })`,或者 `db.colA.find({$where : function (){ return this.page > 150 ; }})`。 地理位置: `$geoWithin ` 选出特定地理范围内的数据。 `$geoIntersects ` 选出地理位置有重合的数据。 `$near ` 按距离倒序给出100 个离给定的点最近的数据。 `$nearSphere ` 按球面距离倒序给出100 个离给定的点最近的数据。 数组相关: `$all ` 筛选出包含所有指定元素的数组。`{tags: {$all : ["aaa" , "bbb" ]}}`等价于`{$and : [{tags: "aaa" }, {tags: "bbb" }]}`。 `$elemMatch ` 筛选出至少有一个符合条件的数组。`{page: {$elemMatch : {$gte : 100 , $lt : 150 }}}` `$size ` 筛选出特定长度的数组。 注释: `$comment ` 给查询语句写注释。`{tags: {$mod : [2 , 0 ]}, $comment : '找偶数' }`。
查询字段
查询时默认返回所有字段,find
的第二个参数可以限定返回的字段(不管怎么限定,_id是一定会返回的):
db.colA.find({}, {page: 1 , readers: 1 }) db.colA.find({}, {page: 0 , readers: 0 }) db.colA.find({}, {page: 0 , readers: 1 })
结果排序:
> db.colA.find({}, {page: 1 }).sort({page: -1 })
限制结果数量
这个做分页时会用到。
db.colA.find().limit(10 ) db.colA.find().skip(1 ).limit(10 ) db.colA.find().limit(10 ).count() db.colA.find().limit(10 ).count(true ) db.colA.find({}, {readers: {$slice: 5 }})