MongoDB学习笔记02:基本操作

文章转自: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 >= 1ms
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的命令列表
db.serverStatus() // 打印mongo当前状态
show dbs // 列出所有db
use nisnaker // 切换到指定db,或者,如果不存在则直接创建db
show collections // 查看当前db下的集合名称,同 db.getCollectionNames()
db.stats() // 打印当前db信息
db.dropDatabase() // 删除当前db
db.cloneCollection() // 从远程复制集合
db.cloneDatabase() // 从远程复制db
db.copyDatabase() // 复制db
db.currentOp() // 查看当前任务,类似MySql的'show processlist'
db.killOp(opid) // 终止任务
db.getLastError() // 打印上次错误
db.getMongo() // 查看当前连接
db.getName() // 查看当前db名称
db.hostInfo() // 查看mongod机器信息
db.isMaster() // 是否主库
db.repairDatabase() // 修复db数据
db.serverBuildInfo() // mongod编译信息
db.serverStatus() // 服务器状态
db.shutdownServer() // 关闭mongod服务

对集合的操作


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'
})

// 相当于 delete from colA where 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'}
)

// 相当于 update colA set book = 'book AAA' where book = 'book A'
// 好吧其实我是骗你的,这样更新之后,之前'book A'那条数据的page也没有了。结果如下:
> 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中原本不存在的键cover,更新的时候会新增进去

$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键,则跟updateupsert功能一样,如果集合中对应的_id不存在,则直接插入;如果存在,就整体更新文档。

如果文档中没有_id,则直接插入,和insert作用一样。

使用和insert一样,如果文档中有_id,则跟updateupsert

查询

好了,现在来看看query,怎么从庞大复杂的数据中,拿到我们想要的。


> db.colA.find({book: "book B"}) // select * from colA where book = 'book B'
{ "_id" : ObjectId("55b213fcd48beedae8d87275"), "book" : "book B", "page" : 200, "readers" : [ ] }

> db.colA.find({book: 'book B', page: {$gt: 150}}, {book: 1}) // select book from colA where book = 'book B' and page > 150
{ "_id" : ObjectId("55b213fcd48beedae8d87275"), "book" : "book B" }

> db.colA.count({book: 'book B', page: {$gt: 150}}) // select count(_id) from colA where book = 'book B' and page > 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/#op._S_type 。

求值相关:
`$mod` 取模,`{page: {$mod: [4, 3]}}`,找出除4余数为3的数据。
`$regex` 正则,`{name: {$regex: /^test/i}}`。
`$text` 文本搜索。这个比较复杂,详细文档在这里: http://docs.mongodb.org/manual/reference/operator/query/text/#op._S_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}) // 只返回`page`和`readers`
db.colA.find({}, {page: 0, readers: 0}) // 只返回`page`和`readers`之外的字段
db.colA.find({}, {page: 0, readers: 1}) // 会冲突,因为限定条件不清晰
结果排序:

> db.colA.find({}, {page: 1}).sort({page: -1}) // 按照页码降序排列,1为升序
限制结果数量

这个做分页时会用到。


db.colA.find().limit(10) // 相当于SQL的'limit 10'
db.colA.find().skip(1).limit(10) // 相当于SQL的'limit 1, 10'
db.colA.find().limit(10).count() // 这个很奇葩,返回colA中所有记录的数量,而不一定是10
db.colA.find().limit(10).count(true) // 这个才是返回limit之后的记录数
db.colA.find({}, {readers: {$slice: 5}}) // 每本书的读者里,只返回5个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值