修改器:
$inc: 增加已有的键值,如果键值不存在就创建一个
数据库中存在这样的数据:
{ "_id" : 0, "url": "www.example.com", "count" : 1 }
db.fzk.update({"url" : "www.example.com"}, {"$inc" : {"count" : 1}})
$set : 指定一个字段的值,如果字段不存在那么就创建它,还可以修改键对应值的类型
$unset : 将这个键可以完全删掉
$push : 向已有的数组的末位增加一个元素,如果没有就创建一个新的数组
$each : 可以一次$push 多个数据,下面向数组中放置了两个值。
db.fzk.update( {"_id" : 0}, {"$push": {"type": {"$each" : ["java", "python"]}}} )
$slice : 限制数组的长度,接负整数。可以与$each搭配使用。
db.fzk.update( {"_id" : 0}, {"$push": {"top10": {"$each" : ["java", "python"],
"$slice" : "-10"}}} )
如果小于10,全部保留,如果大于10,只保留最后的10个元素。$slice后跟的只能是负整数
$ne : 将数组作为数据集合使用,保证数组内的元素不会重复。
db.fzk.update( {"namelist" : {"$ne" : "fzk" }}, {"$push": {"namelist": "fzk"}} )
$addToSet : 有些情况$ne使用不了就需要使用$addToSet $addToSet可以和$each一起使用,$ne就不可以
db.fzk.update( {"_id" : 0}, {"$addToSet": {"namelist": "fzk"}} )
$pop : 从数组的任意一端删除元素
{$pop : { "key" : -1} } 从数组头部删除一个元素 {$pop : { "key" : 1} } 从数组末尾删除一个元素
$pull : 根据特定条件删除元素
db.lists.insert({"todo" : ["dishes", "laundry", "dry"]})
db.lists.update({}, {"$pull" : {"todo" : "laundry"}})
基于位置的数组修改器 : 数组下标获取 $
db.blob.update({"post" : "post_id"}, {"$inc" : {"comments.0.votes" : 1}})
db.blob.update({"author" : "john"}, {"$set" : {"comments.$.author" : "jim"}}) $通过匹配的进行修改
upsert : 没有找到某个文档会创建一个新的文档,第三个参数为true表示upsert。
db.fzk.update({}, {}, true)
$setOnInsert : 创建的时候需要赋值,但是之后所有更新操作中,这个字段的值都不在改变。
db.users.update({}, {"$setOnInsert" : {"createdAt" : "new Date()"}}, true)
db.users.update({}, {"$setOnInsert" : {"createdAt" : "new Date()"}}, true) 第二次运行的时候会发现createAt字段没有改变。还是插入时候的值
多对个文档进行修改 : 默认情况下,update只会修改一个文档,当第四个参数设置为true后,会对所有匹配的文档进行修改
db.users.update({"_id" : 0}, {"$set" : {"gift" : "happy"}}, false, true)
findAndMofify :
ps = db.runCommend({"findAndMofify" : "processes", #processes 集合名 "query" : {"status" : "READY"}, #query查询的条件 "sort" : {"priority" : -1}, #排序结果的条件 "update" : {"$set" : {"status" : "RUNNING"}} #更新成 })
findAndMofify:字符串,集合名
query:查询文档
sort:排序结果
update: 修改器文档
remove:布尔类型,表示是否删除文档
new : 布尔类型,表示返回更新前的文档还是更新后的文档,默认更新前的
fileds : 文档中需要返回的字段
upsert : 布尔类型,值为true表示是一个upsert,默认false
update 和 remove 必须有一个,也只能有一个,如果没有这个命令会报错。
消除指定的键 : find或findOne指定第二个参数指定返回的键,但是_id总是返回。可以利用 _id : 0 把_id剔除掉
db.users.find({}, {"username" : 1, "email" : 1}) { "_id" : ObjectId("4ba0f0dfd22aa494fd523620"), "username" : "joe", "email" : "joe@example.com" } db.users.find({}, {"username" : 1, "_id" : 0}) { "username" : "joe", }
$lt、 $lte、 $gt、 $gte分别对应<、 <=、 >、 >=
db.users.find({"age" : {"$gte" : 18, "$lte" : 30}})
$or $in $nin
db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}}) db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}}) db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]}) db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}}, {"winner" : true}]})
$not $mod(取模)
db.users.find({"id_num" : {"$mod" : [5, 1]}}) #1 6 11 16 db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})
null : 即会匹配本身为null的数据,又会匹配其他文档不包含这个字段的数据。用exists消除不包含的字段
db.c.find({"z" : {"$in" : [null], "$exists" : true}}) #使用in看起来很不舒服,但是没有$eq操作符
正则 : MongoDB使用Perl兼容的正则表达式(PCRE)库来匹配正则表达式
db.users.find({"name" : /joe/i}) #i是正则表达式标志,可有可无 db.foo.insert({"bar" : /baz/}) #支持正则表达式匹配,就是数据库存的就是正则表达式 db.foo.find({"bar" : /baz/})
数组查询
db.food.insert({"fruit" : ["apple", "banana", "peach"]}) db.food.find({"fruit" : "banana"}) db.food.insert({"_id" : 1, "fruit" : ["apple", "banana", "peach"]}) db.food.insert({"_id" : 2, "fruit" : ["apple", "kumquat", "orange"]}) db.food.insert({"_id" : 3, "fruit" : ["cherry", "banana", "apple"]})
# $all会匹配一组元素 db.food.find({fruit : {$all : ["apple", "banana"]}}) # _id=1 _id=3会匹配
{fruit : {$all : ['apple']}和{fruit : 'apple'} #查询结果完成一样 db.food.find({"fruit" : ["apple", "banana"]}) #精确匹配,必须一致,这个不会匹配任何一条 db.food.find({"fruit.2" : "peach"}) #可以利用数组下标匹配
$size : 查询特定长度的数组,但是$size并不能并不能与其他查询条件(eg:$gt)组合使用
db.food.find({"fruit" : {"$size" : 3}})
$slice :
db.blog.posts.findOne(criteria, {"comments" : {"$slice" : 10}}) #头十条 db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -10}}) #后十条 db.blog.posts.findOne(criteria, {"comments" : {"$slice" : [23, 10]}}) #从第24条开始取到33条,不够33返回24后所有的 db.blog.posts.findOne(criteria, {"comments" : {"$slice" : -1}}) #$slice 默认会返回文档的所有键 下面title和content都返回了 结果:{ "_id" : ObjectId("4b2d75476cc613d5ee930164"),
"title" : "A blog post", "content" : "...", "comments" : [ { "name" : "bob", "email" : "bob@example.com", "content" : "good post." } ] }
db.blog.posts.find({"comments.name" : "bob"}, {"comments.$" : 1}) # $操作符得到一个匹配的元素,但是这样只会返回第一个匹配的文档,如果有多条comments,只有第一条会返回
{
"_id" : ObjectId("4b2d75476cc613d5ee930164"),
"comments" : [
{
"name" : "bob",
"email" : "bob@example.com",
"content" : "good post."
}
]
}
数组和范围查询
{"x" : 5} {"x" : 15} {"x" : 25} {"x" : [5, 25]} > db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}) #会返回两条数据 因为5小于20,25大于10 {"x" : 15} {"x" : [5, 25]}
> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}) #没有结果匹配,因为15不是一个数组
# 如果当前查询的字段上创建过索引,现在这个查询只会遍历位于10和20之间的索引,不在与5和25比较。只有当前查询的字段上建立过索引时,才可以使用ming()和max(),而且必须为这个索引的所有字段指定min和max
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}).min({"x" : 10}).max({"x" : 20})
{"x" : 15}
查询内嵌文档
{ "name" : { "first" : "Joe", "last" : "Schmoe" }, "age" : 45 }
> db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}}) # 可以匹配,但是这个和顺序还有关系,如果first和last调换位置,就不能匹配
> db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})
> db.blog.find()
{
"content" : "...",
"comments" : [
{
"author" : "joe",
"score" : 3,
"comment" : "nice post"
},
{
"author" : "mary",
"score" : 6,
"comment" : "terrible post"
}
]
}
> db.blog.find({"comments" : {"author" : "joe","score" : {"$gte" : 5}}}) #这种方法不对,joe会匹配第一个,$gte : 5会匹配第二个,所以返回值还是这个文档
> db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe", "score" : {"$gte" : 5}}}}) #正确写法
$where
> db.foo.insert({"apple" : 1, "banana" : 6, "peach" : 3}) > db.foo.insert({"apple" : 8, "spinach" : 4, "watermelon" : 4})
#想获取两个键具有相同值的文档
> db.foo.find({"$where" : function () {
... for (var current in this) {
... for (var other in this) {
... if (current != other && this[current] == this[other]) {
... return true;
... }
... }
... }
... return false;
... }});
如果true,文档就作为结果集的一部分返回,如果false,就不返回。
高级查询选项 $maxscan $min $max $showDiskLoc
> db.foo.find(criteria)._addSpecial("$maxscan", 20) #指定扫描文档数量的上限
> db.foo.find()._addSpecial('$showDiskLoc',true) #返回该条记录在磁盘的位置
获取一致结果 快照(需要知道mongodb的存储过程)
> db.foo.find().snapshot()
唯一索引
> db.users.ensureIndex({"username" : 1}, {"unique" : true})
> db.people.ensureIndex({"username" : 1}, {"unique" : true, "dropDups" : true}) #dropDups在创建索引时会删除索引重复的文档,并不知道会是哪一个,慎重
sparse : 唯一索引会把null看做值,所以无法将多个缺少唯一索引中的键的文档插入到一个集合里。sparse是这个字段可能存在可能不存在,当这个键存在时必须是唯一的
#创建稀松索引语法
> db.ensureIndex({"email" : 1}, {"unique" : true, "sparse" : true}) #用unique和sparse组合可以达到如果存在这个键,键对应的值就比需是唯一的目的
> db.ensureIndex({"email" : 1}, {"sparse" : true}) # sparse可以不是唯一的
> db.foo.find() { "_id" : 0 } { "_id" : 1, "x" : 1 } { "_id" : 2, "x" : 2 } { "_id" : 3, "x" : 3 }
> db.foo.find({"x" : {"$ne" : 2}}) #没有sparse index
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 2, "x" : 2 }
{ "_id" : 3, "x" : 3 }
> db.foo.find({"x" : {"$ne" : 2}}) #x上建了sparse index时 _id为0的没有查到 如果还想要这样的数据,需要hint()进行全盘扫描
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }
强制全盘扫描
> db.entries.find({"created_at" : {"$lt" : hourAgo}}).hint({"$natural" : 1})
删除索引
db.people.dropIndex("x_1_y_1") #是根据索引名删除
db.people.getIndexes() #查看所有索引信息
固定集合
> db.createCollection("my_collection", {"capped" : true, "size" : 100000});
> db.createCollection("my_collection2", {"capped" : true, "size" : 100000, "max" : 100}); #创建名为my_collection2的集合,大小100000字节,最多100条文档
> db.runCommand({"convertToCapped" : "test", "size" : 10000}); #将非固定集合转为固定集合
> db.my_collection.find().sort({"$natural" : -1}) #固定集合的自然排序就是文档的插入顺序
TTL索引(time-to-live index)
> db.foo.ensureIndex({"lastUpdated" : 1}, {"expireAfterSecs" : 60*60*24}) #lastUpdated超过预计时间这条文档就删除
聚合
> db.articles.aggregate({"$project" : {"author" : 1}}, #将author和_id投射出来 ... {"$group" : {"_id" : "$author", "count" : {"$sum" : 1}}}, #将_id的值设为author的值,没出现一次count +1 ... {"$sort" : {"count" : -1}}, # 将count降序排序 ... {"$limit" : 5}) #取前五条数据
$match 对文档进行筛选
可与所有常规操作符连用($gt/$lt/$in等)
用法:{$match : {"state" : "usa"}}
$project从子文档中提取字段
db.users.aggregate({"$project" : {"userId" : "$_id", "_id" : 0}}) #注意$_id,可以使用$fieldname代替文档中的字符值
1.管道表达式
最简单的是$fieldname,也可以将多个字面量组合
2.数学表达式
"$add" : [expr1[, expr2, ..., exprN]] 加
"$subtract" : [expr1, expr2] 减
"$multiply" : [expr1[, expr2, ..., exprN]] 乘
"$divide" : [expr1, expr2] 除
"$mod" : [expr1, expr2] 取余
用法:
> db.employees.aggregate(
... {
... "$project" : {
... "totalPay" : {
... "$subtract" : [{"$add" : ["$salary", "$bonus"]}, "$401k"]
... }
... }
... })
3.日期表达式
"$year" , "$month" , "$week" ,"$dayOfMonth" , "$dayOfWeek" , "$dayOfYear" , "$hour" , "$minute" , "$second"
用法:
> db.employees.aggregate(
... {
... "$project" : {
... "tenure" : {
... "$subtract" : [{"$year" : new Date()}, {"$year" : "$hireDate"}]
... }
... }
... })
4.字符串表达式
"$substr" : [expr, startOffset, numToReturn]
"$concat" : [expr1[, expr2, ..., exprN]]
"$toLower" : expr
"$toLower" : expr
"$toUpper" : expr
用法:一个生成 j.doe@example.com 的例子
> db.employees.aggregate(
... {
... "$project" : {
... "email" : {
... "$concat" : [
... {"$substr" : ["$firstName", 0, 1]},
... ".",
... "$lastName",
... "@example.com"
... ]
... }
... }
... })
5.逻辑表达式
"$cmp" : [expr1, expr2]
"$strcasecmp" : [string1, string2]
"$eq"/"$ne"/"$gt"/"$gte"/"$lt"/"$lte" : [expr1, expr2]
"$and" : [expr1[, expr2, ..., exprN]]
"$or" : [expr1[, expr2, ..., exprN]]
"$not" : expr
"$cond" : [booleanExpr, trueExpr, falseExpr] #booleanExpr为true就返回trueExpr,false就返回falseExpr
"$ifNull" : [expr, replacementExpr] #null就返回replacementExpr,否则expr
6.一个提取的例子(老师喜欢的100分其他的 出勤10%、日常30%、期末60%)
> db.students.aggregate(
... {
... "$project" : {
... "grade" : {
... "$cond" : [
... "$teachersPet",
... 100, // if
... {// else
... "$add" : [
... {"$multiply" : [.1, "$attendanceAvg"]},
... {"$multiply" : [.3, "$quizzAvg"]},
... {"$multiply" : [.6, "$testAvg"]}
... ]
... }
... ]
... }
... }
... })
$group 分组
1.分组操作符
可以对每个分组进行计算,比如之前的$sum
2.算数操作符
"$sum" 和 "$average"
3.极值操作符
"$max" : expr
"$min" : expr
"$first" : expr
"$last" : expr
用法:
> db.scores.aggregate(
... {
... "$group" : {
... "_id" : "$grade",
... "lowestScore" : {"$min" : "$score"},
... "highestScore" : {"$max" : "$score"}
... }
... })
4.数组操作符
"$addToSet" : expr
"$push" : expr
$unwind
拆分,数组中的每个值拆分成单独的文档
将comments拆分出来,取到作者为Mark的comment
> db.blog.aggregate({"$project" : {"comments" : "$comments"}},
... {"$unwind" : "$comments"},
... {"$match" : {"comments.author" : "Mark"}})
$sort
> db.employees.aggregate(
... {
... "$project" : {
... "compensation" : {
... "$add" : ["$salary", "$bonus"]
... },
... "name" : 1
... }
... },
... {
... "$sort" : {"compensation" : -1, "name" : 1}
... })
$limit
取前n个文档
$skip
跳过前n个文档