您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 16076|回复: 0
打印 上一主题 下一主题

[php学习资料] MongoDB高级查询用法大全

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:+ F: X: d1 ]9 T) I$ l

, O) L5 Q4 c9 i. ?: I7 [9 Z7 n  l1 ) . 大于,小于,大于或等于,小于或等于
& E$ h  g1 |/ A/ I% b1 c# ^, B- ?) ]: H# K8 {5 Z/ p4 c
$gt:大于1 z% X/ Y4 `4 e1 n; l
$lt:小于3 s7 ~2 m* p* Z! @7 {7 g" |1 p
$gte:大于或等于0 x* T; J* i& n# O. B" E
$lte:小于或等于
( s; w6 J$ p" J
: K! Q7 Q  h. t8 t例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value) j% `% U6 ~" M4 l( d8 @/ U
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value! A/ p# }: t1 b  ?" B& g+ K0 w
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value, I! n$ d) H7 I) \, F
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

0 [& d( o; K4 k7 P4 k
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});* @% K$ a" d2 p/ J6 u3 o* g* D
  2. db.things.find({j : {$gte: 4}});
复制代码

3 U- `' v, z' R6 L* ?0 u. d" c
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

6 M7 b5 f6 Q+ |- L9 i6 k% H5 p. b: X8 o: y
) n4 P" a' s6 Y# S  ]3 |
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
# e& ]6 F1 H9 w
3) in 和 not in ($in $nin)
6 M# A$ A) i" _! q* H# \( k
" e4 b; l) E% Y, |1 v8 `语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

, M) f* R. L2 h. w
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    ( ]0 R- d! s) l8 \
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
/ r/ _& ]* A$ m: p- N: j$ e
/ q5 t% h% {( ?, V/ w7 h6 w$ q
4) 取模运算$mod/ T' M1 O3 m/ p
" C4 h7 R* ]1 a& j
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

2 Q/ l: e( u: ?  O8 r6 I) P7 r
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
1 ^3 m2 ?4 p" [, f8 u
- q2 u/ H  Z6 _6 a/ D3 k. Z" [
5)  $all) T  p/ G. n& m/ s0 p( H* u
" j% o: h0 N" a' ?5 H
$all和$in类似,但是他需要匹配条件内所有的值:" J. S2 Q; S- e7 |) {1 m/ C/ \
5 M$ u$ r+ h  Q1 }
如有一个对象:
. E( j3 u$ {8 S) s7 k! q6 P
  1. { a: [ 1, 2, 3 ] }
复制代码

- N0 U4 H8 G1 L# K
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

. S: Z6 c; K. {- E
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

) j9 ?8 k7 d4 m
; R3 v3 f$ f( z
6)  $size
& B$ G9 K) o% L# g: ]6 R0 D+ @3 P# Z3 f9 ~
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:5 d% p0 u: }1 [. i4 y% |
* {" C, L0 d' o/ A
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
$ ^9 \1 }' o$ J1 D
官网上说不能用来匹配一个范围内的元素,如果想找$size<5之类的,他们建议创建一个字段来保存元素的数量。
You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.

8 p, q* F. n- R, e) E& h7 V
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回+ \( w6 ~0 _" z
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

! c/ o/ J9 w; b" `9 V6 z8 h5 s
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string# X) S' w' c' e0 O
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
' n5 G( E5 |* ^5 I: Z
9)正则表达式
7 l% p% }$ ^1 g+ C/ i% u; U" A2 `* A/ Q+ E3 X& I6 e
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

# v! n  n2 r1 A
10)  查询数据内的值
6 k1 g" h; M. D; k& j6 l
0 r9 x+ ]: ?% w2 A% N下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
5 s( k; P# E# g. h; c. p5 F
11) $elemMatch
7 w: _3 v6 f/ q( @/ T3 B& L- p* b* E5 I9 A4 H8 E
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 4 y) W2 S- A) ]
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  1 J# E0 d" M# U7 u8 J2 _
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]: I& n0 k! ]! z. H3 I
  4. }
复制代码
; d9 x8 Y! H' N  O2 g
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } ); o8 H2 L9 d1 \  S- D9 w
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } . }2 O' q# t) n1 S: Z3 w  g% o
& d  X/ i  m' n
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
! T% t6 F9 `$ F; w% g7 B
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

" [: c, [8 Z7 B  U( q2 k2 ^
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
; u3 a& M5 a0 v3 \' r9 T6 ]" C
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
% r/ P  M8 j1 _
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
* J8 ~) ^/ E( U' s# v
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
1 C; x, \  M. Q( T) w
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );$ i7 |( U1 y1 \; B* r
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

* h8 p3 D& h, k/ x
mongodb还有很多函数可以用,如排序,统计等,请参考原文。& O- ]/ ]( d( P; E- {; _7 E: [' s

5 _9 ~& X5 F- e9 Q$ Gmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:7 V9 J' o+ H7 D- I; l7 o
" U: q! [  T3 Q
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions7 Q* ^( ~# g0 U' _  B
: M- v( q3 y+ m+ s4 d( U
版本二:
/ N- [5 u+ M) H5 m. x6 i/ O3 ?6 k8 ?
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
* [2 r) a+ I3 J- \  R
  1. use admin
复制代码

* U& K6 K% W' E/ n7 n
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
2 K; S- L4 {, R& g6 A
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

: J% F  y& P. Q* f! `5 O4 K
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

, L& [3 i, x8 W: Q" Y1 m
         5. #删除用户
  1.           db.removeUser('name')
复制代码
7 J; I) E$ N2 o# u' C! [
         6. #查看所有用户
  1.           show users
复制代码

: ^8 H5 T5 y3 u; ?& A: c% H' Q
         7. #查看所有数据库
  1.           show dbs
复制代码
: v, O2 [. {0 S
         8. #查看所有的collection
  1.           show collections
复制代码
6 u. T6 A7 U, W7 [3 E
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

" ]6 r1 \1 n/ P: Z5 n) C
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
7 Z* r* a! F( |' l
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

- H$ b$ c/ H9 E! h* z6 n, F0 F3 W  s
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

( k) F, L$ X$ O
        13. #查看profiling
  1.           show profile
复制代码
; }3 n0 L3 [! c" `4 v0 Z
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
8 G6 K& N% `' s+ Z* U5 ~2 L2 U
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
' Y0 r& K* W4 }* Z6 z7 d
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

# s3 s: X! y8 k" a
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
" V& M6 ~2 _- j; H+ t# r
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

1 k2 O  N' {$ }! Q  z
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

1 [+ L; q* n0 h" e9 u9 N4 o: K; Y+ j
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

5 U" f4 F' g" K+ i- U
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
( b5 \; F" x6 h" b1 S4 C( l) |
   3. 索引
         1. #增加索引:1(ascending),-1(descending)
         2. db.foo.ensureIndex({firstname: 1, lastname: 1}, {unique: true});
         3. #索引子对象
         4. db.user_addr.ensureIndex({'Al.Em': 1})
         5. #查看索引信息
         6. db.foo.getIndexes()
         7. db.foo.getIndexKeys()
         8. #根据索引名删除索引
         9. db.user_addr.dropIndex('Al.Em_1')
   4. 查询
         1. #查找所有
        2. db.foo.find()
        3. #查找一条记录
        4. db.foo.findOne()
        5. #根据条件检索10条记录
        6. db.foo.find({'msg':'Hello 1'}).limit(10)
        7. #sort排序
        8. db.deliver_status.find({'From':'ixigua@sina.com'}).sort({'Dt',-1})
         9. db.deliver_status.find().sort({'Ct':-1}).limit(1)
        10. #count操作
        11. db.user_addr.count()
        12. #distinct操作,查询指定列,去重复
        13. db.foo.distinct('msg')
        14. #”>=”操作
        15. db.foo.find({"timestamp": {"$gte" : 2}})
        16. #子对象的查找
        17. db.foo.find({'address.city':'beijing'})
   5. 管理
         1. #查看collection数据的大小
         2. db.deliver_status.dataSize()
         3. #查看colleciont状态
         4. db.deliver_status.stats()
         5. #查询所有索引的大小
         6. db.deliver_status.totalIndexSize()
! L, U5 X* }6 ~; L
6.  高级查询
条件操作符
  y+ S7 I4 d3 H" E5 y) `  C
  1. $gt : > ; q) c& A& ?5 ]! H1 x$ e
  2. $lt : < 2 }; w5 X# N! ~! }7 f/ `( n
  3. $gte: >=
    : S, r0 A& o; R: a  d" g1 h
  4. $lte: <=
    4 B6 S2 l2 L( W1 Q9 {
  5. $ne : !=、<>
      c5 C+ T# E8 _  U( ^
  6. $in : in ' P$ \2 N* Z" Y$ ^. O0 S! Z# W
  7. $nin: not in
    4 Z9 w6 Q! u( V
  8. $all: all 0 X% @3 _, P. ?1 `; \
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
6 o1 }, w% `; Z. y, W3 c0 s

- \3 _+ r& [+ t: A查询 name <> "bruce" and age >= 18 的数据
# j3 A' q' p' f- {
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
: w/ X0 ~/ o; o$ U4 B
: R& R( c1 f, k4 l& g: E
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 9 z- V* p" Q# h& F  d
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
+ z& I6 n4 V9 I1 M

* i2 X2 j! E& a9 i/ q查询 age in (20,22,24,26) 的数据
( w" b% u% e/ v0 I& c
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

' J" S, f4 x+ ^/ K" p
5 M7 Y% R6 Q! L4 H  @查询 age取模10等于0 的数据
) x; _& z1 k% t% g2 t6 K
  1. db.users.find('this.age % 10 == 0');
复制代码
( `" d" U5 a6 G7 I+ P$ g
或者 : a  d: x& r. \% t
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
( k$ u4 n- S% N( F- O
  i: D6 U7 N- z1 T: F
匹配所有
/ N, q6 g# ]1 W  C% `
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% J9 L5 Z  `9 \: H9 Z
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } + e) h& N* h( q. o, z: e/ f% S
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
* y$ b* i7 i$ D- R' T$ w" ^4 L( z& ]% }# S' ]- K; K
查询不匹配name=B*带头的记录 4 t; b1 [4 _- I1 f" {& m6 ]  F6 b
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
+ }  P" M7 G' c+ Z& I
查询 age取模10不等于0 的数据
5 W! y) ^. t* U1 Q: e: u
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

2 \$ a9 i% E& o* @# C5 h+ h4 O6 v8 E; G9 v3 G% B  T# S
#返回部分字段
% N! I1 N0 Q& z+ Q* b选择返回age和_id字段(_id字段总是会被返回) - [1 g- p- ~) h; u( w: W1 X0 z8 `
  1. db.users.find({}, {age:1}); ' R& r) K) u' z
  2. db.users.find({}, {age:3});
    : k% A/ H1 I# ?- W& L
  3. db.users.find({}, {age:true}); : X" y/ `9 @- @% i, P% q& D& g8 c
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
7 x4 F$ A! z  p! @7 t! k4 x! O
0为false, 非0为true
  V9 Y7 K+ L: ?/ K8 G  d( P5 Z# E5 P
选择返回age、address和_id字段 ) y5 ^2 q. z: O! a
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
0 R  o; J/ }$ X6 F, \
7 R$ j+ C/ c" l7 `3 |7 j6 j, F0 p
排除返回age、address和_id字段
+ J0 ]/ ~; a" g4 a0 B4 n, t4 U' Z
  1. db.users.find({}, {age:0, address:false}); & r7 z+ c7 f8 ~7 W" u) c3 {
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
# l: t, S* Z& K$ U8 Y

( F" y7 N, s6 W数组元素个数判断
# R. o+ r" [2 b4 B$ U+ f对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
: r# t5 d. a0 D' U( i: A; w匹配db.users.find({favorite_number: {$size: 3}}); * g' `# p) T# E$ \, p
不匹配db.users.find({favorite_number: {$size: 2}});
3 \+ D. c5 \# k- s" _4 F5 H4 z+ L5 t
$exists判断字段是否存在 7 `) M4 |2 l, N5 J  a& g
查询所有存在name字段的记录 ' Q2 Z& |' [( D1 }3 l9 v
  1. db.users.find({name: {$exists: true}});
复制代码
3 K& M" E; G. s9 [
查询所有不存在phone字段的记录   j3 l! n" g' X4 {6 @' X
  1. db.users.find({phone: {$exists: false}});
复制代码
3 g) W# i3 u% A" E

1 |) Y% A8 x0 Z( ]* v5 Y% x$type判断字段类型
' _: L" H  n  b9 m! N5 c: f查询所有name字段是字符类型的
  k" h( m0 @% D4 l
  1. db.users.find({name: {$type: 2}});
    $ n2 I$ Y. H/ t, w1 h4 b
复制代码
  f  F- i- u8 `! ^1 k$ d$ N3 H
查询所有age字段是整型的 2 e1 B3 ?9 T+ f( y) N0 l
  1. db.users.find({age: {$type: 16}}); 4 X+ P* G8 m9 t; B
复制代码
! O5 T. j: y# m7 i0 w) e0 k
对于字符字段,可以使用正则表达式 2 H# n: V; F0 E; v
查询以字母b或者B带头的所有记录
' @' r$ c; |# ?* }8 p: N3 {( i: O
  1. db.users.find({name: /^b.*/i}); . T; k+ j1 W* H) M# x1 Q
复制代码
$ u* B  H- ~8 E, {% e
$elemMatch(1.3.1及以上版本)
6 H, t, u' m# z, L为数组的字段中匹配其中某个元素 # H& }" I/ d. N; J' x

; Q/ g( C& Q0 h, j5 L; IJavascript查询和$where查询
2 h/ ?. G1 r! \5 c# c, N8 c查询 age > 18 的记录,以下查询都一样 0 o3 u7 g4 X6 }1 ~: M
  1. db.users.find({age: {$gt: 18}}); 4 a  A+ [6 p& D: P7 I% f' S
  2. db.users.find({$where: "this.age > 18"}); + m4 R8 s' O8 P& k, s# I: i
  3. db.users.find("this.age > 18"); + n* Z# R% ^( H4 J1 g# B) Z  N& K
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

/ b5 Y% O9 z6 f0 I! t4 S  f9 i4 v- B
排序sort()
9 C0 L, n" y( }, ^* ~以年龄升序asc
9 y( W7 G& V/ C5 l& r
  1. db.users.find().sort({age: 1});
    % m3 Q; S" P5 c8 X) V) K; ^1 U
复制代码
* }  @5 y) p5 }$ z( G
以年龄降序desc
% Q9 p6 i9 h/ H& }( d+ f
  1. db.users.find().sort({age: -1}); ; G" i3 _: p' e1 }1 G
复制代码

5 h8 V3 e$ N$ Y7 x+ r: C5 D+ `; d限制返回记录数量limit()
  k" a% f" s, b返回5条记录 ; [0 ]- Y9 ]& ?
  1. db.users.find().limit(5); , u  }& @! m& O/ w* Q3 `4 f% u( C
复制代码
3 [( o/ Q6 F  x- Z# f) D. h, g" W' i
返回3条记录并打印信息
7 i% F' [4 b: O
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 6 q, x: q# B5 f) k+ @9 v
复制代码
# |# c8 @) L2 H  G' R6 S
结果
1 L, m0 G0 J1 p" o+ ]1 y1 ?
  1. my age is 18
    , f& H0 O1 V; k. W0 E
  2. my age is 19
    " }. o- M3 v" \' G+ O% v+ q/ W
  3. my age is 20
复制代码
  g/ p% P9 l8 I! z8 _( D
! T9 I6 }( O& Y( q7 ~7 V
限制返回记录的开始点skip() 6 J7 E. [/ p9 |- X/ p; F' Q" x1 x9 o
从第3条记录开始,返回5条记录(limit 3, 5)
" v' Y. A* K6 p, n
  1. db.users.find().skip(3).limit(5); 2 i/ S: J# `- U# A: J+ {
复制代码

4 o% x# K0 E! f查询记录条数count()
% Q& x( D3 ~5 B' P; D2 _7 ndb.users.find().count();
( L; y5 l8 `5 l; Odb.users.find({age:18}).count(); % M& T/ w/ z4 r; F1 w( W
以下返回的不是5,而是user表中所有的记录数量
' y' z' I. f- m0 a3 wdb.users.find().skip(10).limit(5).count();
' F6 O, W8 O; a* y  h+ G. Q' V如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 7 C! V1 d' S! m5 N) K
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

5 x6 |2 k. K2 B* ]* w+ ]
7 |4 y8 c" o; D, j1 `; y0 ]4 }分组group()
' e9 _( z; d% I4 L* |6 |假设test表只有以下一条数据
% I* e+ j" G6 y0 Q9 O% U& @
  1. { domain: "www.mongodb.org" ! l& e6 g' q% q9 u. I# v, L
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} / m- t6 M6 T& |6 L
  3. , response_time: 0.05 ; t$ k* _4 P$ v' r; r. z
  4. , http_action: "GET /display/DOCS/Aggregation"
    ) N- r: B- q- Z+ o/ ]
  5. }
复制代码

5 A8 I# V7 N7 i. H  G! G1 @1 Q" }使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
& {/ v9 a/ p) [# R/ h  V! c
  1. db.test.group(
    5 R6 h$ S0 C& ~* f% {
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} / j7 u; _+ ^) `1 l* A+ r
  3. , key: {http_action: true} / D7 a7 ~4 I. w, _/ O/ u* i
  4. , initial: {count: 0, total_time:0} $ D% @/ j0 m5 J* t1 c3 x
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } " B- ^- H3 k2 i5 B
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } 7 b# U# l7 v+ f$ `% R
  7. } );
    & y, V) ?* e2 n6 D

  8. ! |' Z# J+ I& s. i* D9 X. }
  9. [ 0 G6 ~% G/ k5 x- O3 H# ^( J
  10. {
    % ?( p9 k5 r: [/ S$ U. H
  11. "http_action" : "GET /display/DOCS/Aggregation", 0 [7 |1 m. S) L( A2 T6 e
  12. "count" : 1, 7 W$ b8 |" A$ |6 ?7 y$ O6 C5 \
  13. "total_time" : 0.05, ; Q$ R; x, ]3 e( T' M/ W
  14. "avg_time" : 0.05 % `: H0 @% k- {% K1 |8 N& X
  15. } / U$ i" F$ M& ^! e7 X: a/ U
  16. ]
复制代码
# J5 m% ?. \6 F, L" x- w

' ^% ^* ^# d7 }3 S$ \7 R# ~5 S( U% Y1 ]- G: B; F
MongoDB 高级聚合查询
MongoDB版本为:2.0.8
系统为:64位Ubuntu 12.04
先给他家看一下我的表结构[Oh sorry, Mongo叫集合]
如你所见,我尽量的模拟现实生活中的场景。这是一个人的实体,他有基本的manId, manName, 有朋友[myFriends],有喜欢的水果[fruits],而且每种水果都有喜欢的权重。
很不好的是你还看见了有个“_class”字段? 因为我是Java开发者, 我还喜欢用Spring,因此我选用了Spring Data Mongo的类库[也算是框架吧,但是我不这么觉得]。
现在有很多人Spring见的腻了也开始烦了。是的,Spring野心很大,他几乎想要垄断Java方面的任何事情。没办法我从使用Spring后就离不开他,以至于其他框架基本上都不用学。我学了Spring的很多,诸如:Spring Security/Spring Integration/Spring Batch等。。。不发明轮子的他已经提供了编程里的很多场景,我利用那些场景解决了工作中的很多问题,也使我的工作变得很高效。从而我又时间学到它更多。Spring Data Mongo封装了mongodb java driver,提供了和SpringJDBC/Template一致编程风格的MongoTemplate。
不说废话了,我们直接来MongoDB吧。
  • Max 和Min
    1 K) ~+ X0 \4 H) u0 f9 j4 P6 b
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

  Z) s% z1 X/ A$ W/ B9 F" V" K4 q" t
0 F6 W. i% p) `! e$ ?0 i
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct8 Q0 a3 J) R6 }
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
, k5 s5 r0 |- X, A
. D$ \! S0 \& r8 ~* `
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

# f% i9 d+ e5 @# Y) b  a* y+ v6 w1 I( s0 T- F% j3 K
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
7 l0 J  Z" _+ U+ H2 a/ w3 v% j7 P) U
4 }- T9 V6 D/ ^
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
8 B! f) B4 b5 q2 n
, [% p# N- j7 `5 i' }3 Q
输出如:
  1.         6 D1 Y2 Q% M9 u! i/ U8 c# r- ?0 S
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
5 B0 z% P6 R2 e! m( I" ?8 l
. ]" b8 }& u# G; c, s
; z8 M# w2 q' E& p/ }$ c
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"* b) b' n! D: h
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"2 V6 a9 e, c1 D/ Y3 J5 A' v
  3.        xmlns:context="http://www.springframework.org/schema/context"
    6 z0 a0 v0 M8 x  @8 [
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    7 e) e: C) j- z# v1 q
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    ' }# K+ A+ m4 e& z, l! k
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    ) }0 i7 U6 C: w9 t. ~& n+ t
  7.           http://www.springframework.org/schema/context
    ' X! `8 x0 A, a% _# H
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd& c0 U5 o/ M* M/ y# E
  9.           http://www.springframework.org/schema/data/mongo
    - d- [5 p4 L  i' L1 _7 L
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
      R+ ?/ W3 t5 T; D: V
  11. : d$ ~, r* G1 ~/ M: P# _; }
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    & r3 R7 I5 z3 I+ o: I1 o7 ?) a* b
  13. % w% a9 Q' u. Y9 |
  14.     <!-- Default bean name is 'mongo' -->" `+ z' G5 s! H2 f0 T! N! k$ F9 O
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    ' I7 l3 _" k! r; Z& @/ s

  16. * X, Z% m. e; |6 b/ B
  17.     <mongo:db-factory id="mongoDbFactory"
    : v, X/ R" _( ?! k; s. T" e
  18.                   mongo-ref="mongo"9 g3 z& L* u3 D3 s/ F: Y
  19.                   dbname="mongotest" />* F/ J0 y/ f) i- ]7 c* Q1 G

  20. 6 m. Q: ^1 t. P5 Y
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">9 r7 @. u+ a  @3 \
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ; ^8 D. y* n3 M/ ~+ \8 M
  23.     </bean>- u( L" N9 f2 \
  24. </beans>
复制代码

* _/ K9 ^# b" O3 b4 y; M. f. I
5 m5 R1 ~2 G5 n$ h  p
maxmin的测试
  1. @Test
    + q7 k9 U4 W- \* p# R( e' K2 V
  2.     public void testMaxAndMinAge() throws Exception {
    * c8 l4 r$ V; n
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);5 b$ J. {; m8 ^3 g
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    - b$ x' d* B' ^/ @
  5.         log.info(result);
    / b2 {! s3 p9 Y4 Q# I3 Y
  6. 4 e9 y( Q2 o. `
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);& s& h, ~, u& Y
  8.         result = mongoTemplate.findOne(q, Person.class);( `# f1 U6 E, h3 C
  9.         log.info(result);
    9 V; |* A7 m2 c6 X# c! z" s
  10.     }
复制代码

7 l  \2 C# E, s  A, h" n5 G& q& n7 r1 Z
distinct的测试:
  1. @Test' G+ X# Y$ x3 ~* T* ]5 z2 a8 A
  2.     public void testDistinct() throws Exception {. \6 q2 G) b/ l1 W- d+ ^
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    - p* a; k9 x" @' ]; {- `1 p
  4.         for (Object o : result) {
    7 R* y5 h1 ?# \! p. v7 m
  5.             log.info(o);
    9 ?7 I" j4 W6 u; I  `
  6.         }
    7 Y6 M0 h/ R6 ]% J6 @* s8 b6 }

  7. 2 `. S% Q' N; c- v2 ?
  8.         log.info("==================================================================");, k1 p% \9 X/ z" P
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));5 D' Y0 j) W, w( e% |9 t
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());5 u7 q: W4 M% H! c! A7 m/ ?: v
  11.         for (Object o : result) {
    * |5 o5 p/ T. V& b3 `
  12.             log.info(o);* I0 n5 B0 Z+ S; h7 d1 U
  13.         }, Z6 N* B) @  [
  14. 0 S! Y6 L# \& [7 I4 Y3 M$ \
  15.         log.info("==================================================================");
    , e# K" A. z% z- a* r' d
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");, C1 d" \$ k2 D: [1 `; Z, o/ m
  17.         for (Object o : result) {5 c2 |7 |* }9 @# E9 i; Z* U
  18.             log.info(o);
    0 m+ @* F8 h/ W. d2 T0 u% B/ ~- r
  19.         }7 F/ a: o, V) l" F- |) a
  20.     }
复制代码
5 w7 c$ _' A4 i! ~' q% @

: Q& X0 l$ b8 I) t
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567: M1 q, k( a$ s0 d/ W
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    - l& ^9 r8 j+ N9 `; _
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    7 R. B7 H! o- _3 L& N
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654' N9 R: f6 l0 z. M9 @1 P" X1 |
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni+ p; t6 u* q2 ~# G4 ~
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    4 c. a% }, X# V; _/ L8 ^4 I! L
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    , A; O- J3 o/ ~2 B$ ]- v: F, `  Y
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================5 R( a5 G- G6 O# o! Y$ l1 _; T* l
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567  b7 y; k3 D$ ^0 ^. |( x
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    & c$ Z7 w6 i) L9 H, S
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789+ u7 w' l' S0 F( u& n4 ^  ?$ \$ z% d
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
      @* O9 j, E  B! V0 P
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    ; P- ^0 _7 W6 n* H. A0 r* f% [
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa! X. c; C5 V+ C0 O; u8 r/ ^
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    ' H5 w" s# T4 r
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    " V  D, o5 W4 P3 H% G+ w  T" h9 ?
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    : A4 l! S3 W  |% |4 D9 ]+ T
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx- v# P9 Z5 T) `  U! F7 s; t1 T1 ]
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy" O7 M, Z4 Y& I
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    % O, {& {% X& p; L
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr# s& l, v& z( L; c
  22. 12-22 14:13:45 [INFO] [support.GenericApplicationContext(1020)] Closing org.springframework.context.support.GenericApplicationContext@1e0a91ff: startup date [Sat Dec 22 14:13:44 CST 2012]; root of context hierarchy
复制代码
8 A* K* g. D8 k& u. N. `0 Z1 {$ b9 Z

: y/ B2 ~% l' o2 a+ V" S# W0 q! J
这里我要特别说明一下, 当使用了Spring Data Mongo,如上面的findOne(query, Person.class)它就会把查询的结果集转换成Person类的对象。Spring Data Mongo的很多API中都这样,让传入了一个Bean的class对象。因为distinct的测试是输出list<String>的,我 使用的mongo-java-driver的api。他们都很简单,唯一的是Query这个Spring提供的对象,希望读者注意,他几乎封装了所有条件 查询,sort,limit等信息。
- V2 Z" n: E- G2 z3 E$ l7 }
$ q$ e2 F8 }8 R5 \
7 L# P% v- y/ B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-20 05:40 , Processed in 0.102108 second(s), 22 queries .

Copyright © 2001-2026 Powered by cncml! X3.2. Theme By cncml!