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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
' [. m0 y* i: `: V* p1 A8 m" O2 v: t' _$ N5 Y. v$ R
1 ) . 大于,小于,大于或等于,小于或等于1 l) I# N2 \* g! e0 k7 {

3 w& E! [) p5 z. c) H: I) O6 m$gt:大于$ _9 y) f* l3 y! U9 ?% D' V
$lt:小于' S) q# b5 M9 `2 V9 @- x  C+ C
$gte:大于或等于* S0 x; X' H. X/ \
$lte:小于或等于$ P$ D5 u, X( q; q; f. ~

' E% D; W1 N. y. v7 o4 i1 a. k例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    : U1 a2 m: e9 R) n+ Y
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value- {( j$ }6 T& `  C# f
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    2 C8 q* p/ A( j0 ?, t
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
/ E  B$ M/ i) `% V( f
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});7 v( A1 w0 x- W+ `
  2. db.things.find({j : {$gte: 4}});
复制代码

  T( g* Q, b; ?+ V& W6 P0 \
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

4 k; q( y. R2 Z5 y+ r- E; ?* @# C
8 F; A( i. ~2 }  q
: O# B* l7 u. l7 L% C
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
8 F+ }  ]. _3 F
3) in 和 not in ($in $nin)
' \* m( H/ R: X7 i/ R9 N6 i% R+ }$ W# |# V* W0 \$ C# ?  r; B
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
  w6 L5 V: k' b. b$ Y# f! M
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    4 v/ S$ @% r/ ]) V$ r
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

5 z! v$ R. M- e$ p! x6 J2 ]

) t9 E6 v5 ~* l; y- a; [( |/ s4) 取模运算$mod) W4 Q; Q0 }3 l/ S
: d$ x" _+ E% R# ^( E3 x) L4 ]# S
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
1 T$ a$ i& y8 |4 Q
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
# ]1 P" w4 t8 x+ N8 O

& B' }( ]9 u4 i" \1 a5)  $all& q- }8 P4 s' D; `3 e
( w9 l; L3 [1 }- ?# P$ M6 r, K# h
$all和$in类似,但是他需要匹配条件内所有的值:
: v& D' P# q& U- A- z) K& ]6 e7 w- f. a& v+ H1 a, ?  `. F, @
如有一个对象:
# L6 J2 K; B: K% O. H/ K) {3 x! Z. g
  1. { a: [ 1, 2, 3 ] }
复制代码
# `+ P) h7 v# x) q( |& o' `$ _# a0 }
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
' u3 \  ^  T% ?# M/ f* X- P
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
, Q) A& W7 K3 z. l2 R8 K  z' P

/ ^' |+ C+ ?( s4 ^6)  $size
- v* D4 f1 y: Q- k% z2 \* R& x7 \0 T3 m# d$ K/ X+ i
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
- C* R  q* T& }* q( I( S5 r' O/ r- F2 |1 {
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

9 S& @" E( ~+ ?) s0 M! H
官网上说不能用来匹配一个范围内的元素,如果想找$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.
: N. c6 W6 t# z, O$ P- y
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回( ?: O3 z* E. v2 o
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
' m1 s6 F3 b3 c; W, L' Y
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string- h, G7 w2 t5 W% ^$ T' M
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
: C0 C( j( i1 V  W6 a. T! E+ u5 B
9)正则表达式+ L# N# z' `" Z  p1 @; Y- G" t
: u& P& _. U4 u: z) n+ B9 P4 H
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
; G3 s4 s: `! ?' A4 v
10)  查询数据内的值
0 G2 Q" ?$ G+ Q; C0 r% z: t( z% c: F/ B, z4 |1 g
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
9 e5 h+ J# G1 z- y& G* G; |
11) $elemMatch
1 W" |8 [- m: m2 `
, l6 X0 G. B1 L9 {8 X- i如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
      i: B1 T4 C+ B" E9 e
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    ; s) W" |+ _& g' ^
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    % _4 h+ B" K# q+ X; L
  4. }
复制代码
9 L3 P+ W5 e7 l& Q
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
- g, m# |2 F( t3 c/ i7 n  o0 M
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 6 V; s+ D+ j2 C4 l! F! c3 p

9 m  j% \" O" _6 E2 Y" \12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

/ y, D" y  k& @
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

8 E- p) V( }6 K* C/ _$ f8 r
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
2 Z& ~  |. a7 s$ v
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
& c" Z+ m* I9 x" D- S/ H
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

+ k* d  C# p# K# L/ |6 E4 }
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

! x4 z+ v" v8 Y! x$ J& K5 Q
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );2 b+ _6 P; l6 ?" J
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

. B0 w/ `4 H" {; e
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
2 }: }5 R: m) @5 z) Q) f% t' ^4 \4 V3 M0 F- G
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
% R1 V5 W; b0 L
9 }* B, q4 h2 A9 G: O7 V  r) L, n; khttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
( a' U& b' D5 y9 V
7 f9 G* ~8 e; h- l% Q* K9 M/ F/ B版本二:
' L* P# k5 Z8 U! A2 n  S- c
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
9 g6 K; e: @8 d7 }  ~# x7 y
  1. use admin
复制代码

# s0 E; C' d! U. p% L- j3 \' b
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
$ J& j5 O& F* K. C0 a
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
- g- e& |7 n! v9 i7 c4 r
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
# l, e. i/ ~+ `4 u) @
         5. #删除用户
  1.           db.removeUser('name')
复制代码

' y1 v6 K& v% E; N, a
         6. #查看所有用户
  1.           show users
复制代码
- U+ o; g* V# r$ z
         7. #查看所有数据库
  1.           show dbs
复制代码
5 O2 a9 ^) [+ |+ q/ x8 W4 u
         8. #查看所有的collection
  1.           show collections
复制代码

; f8 y9 s. V: A- V- }
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
# P: A' ~5 W6 g; w9 E1 O
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

8 k: n4 X. u( t/ n: {
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

* \0 a* W1 z, D# k0 w
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

( V- @- i: ~* }
        13. #查看profiling
  1.           show profile
复制代码

; W* _, B- G" X' _- k0 k
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
" \! i  y3 b, M4 G+ Y+ h. J, w4 A0 t
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

1 w, G. @9 f% B( g& C4 y
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
& D' e# z' u* C! Z3 U( A1 l; R
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
2 o& l( z8 |+ g
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
1 |, j6 ^& {: l
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
" k& j. U; @( L7 Y. {! L" f4 T
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

3 \, c8 P( l; Z
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
. I  V3 @+ ]$ ]9 F- B- Q9 V4 Z3 H
   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()

1 I9 r* Q) i$ n4 C
6.  高级查询
条件操作符
1 x0 b: ]( m9 S. B
  1. $gt : > / q3 t5 y% [3 Q, O/ }
  2. $lt : < 4 c# x9 r' ~: j3 c# f
  3. $gte: >=
    , Z( V* ^- C- l/ Q" f: t- p7 K
  4. $lte: <=
    % L7 G2 O1 C! }- o
  5. $ne : !=、<>
    ( H1 I. t/ k/ U: G+ I( P
  6. $in : in
    9 H! G0 |2 h: q% e
  7. $nin: not in ! m  @) J4 @7 P( m7 u( b: k0 F
  8. $all: all
    ; e# Y7 V! U8 j2 I  Y+ S
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

- o7 D0 i0 a5 j4 N/ F0 O( q
/ P  S! B* x+ L  C  y& i% J查询 name <> "bruce" and age >= 18 的数据
! Y: x2 k+ o" `: i% U! q; r. N
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

  r, S* c' z  \% s9 W# G6 E/ U/ z7 u! u, i  ]+ N5 }
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 . s& g5 ?  J. t3 {9 y
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

8 @4 K( V( a/ t6 b% l5 M
* G# ^& V4 `2 m2 V% j查询 age in (20,22,24,26) 的数据
8 Y1 ~# R: u8 ^% q- Q0 f. C% G, A
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
5 E+ `3 |$ L/ G4 u3 i* r1 \+ e
0 a5 u% a8 C2 E8 s* a+ ]5 ]4 S2 E
查询 age取模10等于0 的数据   D7 [% [9 x& |3 C
  1. db.users.find('this.age % 10 == 0');
复制代码
* M. n# M+ |& {+ v( X- x
或者
- u3 ]* b! ]& y. s7 X
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
; _) D$ @8 d) j/ `5 E
6 v7 \* k. m6 W& R3 @; Z
匹配所有 / C+ j* r8 _2 `$ y3 y% b6 X
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
# Y2 \1 F8 m& P, Y$ x2 d9 z" B
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
7 h3 r, i# a# f2 c可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
8 c0 ~; V- b0 Z1 c+ t7 E3 p) F* t% u
0 R  j6 Z  f' ^5 V/ V查询不匹配name=B*带头的记录
0 d' _4 p; a& Z8 S
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

1 y3 f5 P8 ]2 a3 u& I% k4 A2 t# c2 a* t查询 age取模10不等于0 的数据 * E( \6 O3 M+ M) U" s
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

, A0 t7 l# }( b3 D6 I8 a* O- ^( o4 j4 u6 _( p
#返回部分字段
) e: X+ \, j9 d5 \. l选择返回age和_id字段(_id字段总是会被返回)
( w, W3 {" G% A9 `0 V: y
  1. db.users.find({}, {age:1});
    0 r- y! D% O3 D
  2. db.users.find({}, {age:3}); # [" I: `- t. O/ Y  q
  3. db.users.find({}, {age:true});
    8 X. |- S+ ~5 E2 U/ t
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

3 b2 a$ X3 P2 R: z1 B0为false, 非0为true
! o& N5 s8 U- n5 `6 ^( @, p, r8 @6 `* ~% @/ O! _$ z- x
选择返回age、address和_id字段
% O. ]& p3 {2 k* z( i
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
( z9 D# p9 l4 u$ T5 |) e

# O' B1 x/ T+ W  @( z% p& S排除返回age、address和_id字段 1 T6 J! _# l! \# j5 S; s) y
  1. db.users.find({}, {age:0, address:false});
    1 i  w2 V" l9 ^3 @# _& J' _
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

6 G& Q8 h; t$ ~  A% c
  m9 C1 m, _% Z7 C6 b: @: O数组元素个数判断
9 @8 i3 O& E5 |% d) |/ g对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
; L0 S$ r$ V( H2 |9 d! B匹配db.users.find({favorite_number: {$size: 3}});
. g( b& v( p; {. H+ ?, @不匹配db.users.find({favorite_number: {$size: 2}});
5 \# Z5 i- a, r; m- P7 _& a
" _# T7 Y+ W& {$exists判断字段是否存在
8 J" X. ^' P2 `查询所有存在name字段的记录
) j& Q3 N2 S( A* C
  1. db.users.find({name: {$exists: true}});
复制代码
# q4 ^, Q- Y, J
查询所有不存在phone字段的记录 , V6 R$ C/ Y0 v+ j. ^6 ^. M
  1. db.users.find({phone: {$exists: false}});
复制代码
/ I3 ^" _9 d& t' R1 X) l  P: R% y5 \

4 P! J1 a( ^3 t$type判断字段类型 , g. d( q( l$ u7 l5 T+ c
查询所有name字段是字符类型的
. Y: U9 M; }% B3 P9 ?- ^* x
  1. db.users.find({name: {$type: 2}});
    ) i+ c: M& [: n
复制代码

. H6 ~0 [4 i6 ]- v) r查询所有age字段是整型的   j$ u1 F; `+ s6 Z+ T  V
  1. db.users.find({age: {$type: 16}});
    ; M' v' r& d2 P: b
复制代码

3 ^- R0 W* j1 E/ R2 ]对于字符字段,可以使用正则表达式
5 L' U! f) A% d4 B0 b查询以字母b或者B带头的所有记录
# m" n3 p8 i7 x0 W% y: z7 G
  1. db.users.find({name: /^b.*/i}); - X2 M! t7 o. h, D4 ^6 H* A
复制代码
- Z/ s/ ]  F: K2 k
$elemMatch(1.3.1及以上版本) 5 ]' f( t$ N, E. V# ~. B; c
为数组的字段中匹配其中某个元素
  t+ p8 k9 }4 N6 h' S7 g( c
8 {, m7 |  r0 f8 p6 xJavascript查询和$where查询 # H/ P5 z, h  k" d
查询 age > 18 的记录,以下查询都一样
' }& _  g' n- V# j( @5 {
  1. db.users.find({age: {$gt: 18}});
    & w9 M! _" R/ b2 f
  2. db.users.find({$where: "this.age > 18"}); 9 w4 `  }/ N1 }" D
  3. db.users.find("this.age > 18");
    $ `" E- j& m# F4 u
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
7 |- w& t( K& n

$ q2 B. }  D  h: q- `排序sort()
/ {, e0 e8 z" m以年龄升序asc 5 G/ {0 _" E1 {) g- U
  1. db.users.find().sort({age: 1});
    ; n* }; E, r( w
复制代码
! b! ~. q. z. A* \! p6 c
以年龄降序desc
9 O  v0 H5 L8 i9 L/ K
  1. db.users.find().sort({age: -1});
    0 d! ]+ y! t- ^/ r2 f' j
复制代码

; |7 K7 A4 h# f8 v限制返回记录数量limit()
, a8 l% T5 n( H5 w0 L* Z返回5条记录
1 l7 r' @) ^# \8 J! a) Y* z4 V
  1. db.users.find().limit(5);
    $ {% H5 z6 Z# J- N; T
复制代码
! C4 e7 K, z$ x3 ^; @/ G
返回3条记录并打印信息
' K$ C9 w! S' ?+ r+ s) j% k
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    1 t( G) X6 f6 a- b
复制代码

; f4 y" ^+ U  r- `( V结果
$ l3 B' `6 Y$ A  l. i. U; r
  1. my age is 18 & h6 T$ s, D, j; L4 N) @- [7 S
  2. my age is 19 ; i, c+ V- A2 w2 I% ]
  3. my age is 20
复制代码

" q) V4 S- z" A) a
6 ?( J! c% O# A限制返回记录的开始点skip()   ~1 B6 O  M. O8 c
从第3条记录开始,返回5条记录(limit 3, 5)
& x5 J. D0 B( `; n1 w, u2 y
  1. db.users.find().skip(3).limit(5); * D. W7 b6 C1 {
复制代码

; z, E) \# {. j, v0 `6 Y4 f4 W查询记录条数count() 9 e( f  t+ U; C8 |3 I$ S
db.users.find().count();
; |/ ]2 U/ k" ?8 ~5 }$ P: {db.users.find({age:18}).count(); $ H" c8 \- d. w* _
以下返回的不是5,而是user表中所有的记录数量 2 X: H7 n8 k; k. g& z2 b$ y
db.users.find().skip(10).limit(5).count(); 1 I  I/ b4 _* @8 I, [0 G
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
( T6 k) \1 e& R, u* b" V7 H; p& R
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
/ x6 t% F4 G5 V. K2 r
$ a3 |% ]5 j& e' d/ \" u: R
分组group() % a5 U8 ?2 e. V/ U, X! t3 s5 \
假设test表只有以下一条数据 6 E$ P+ m7 P7 k
  1. { domain: "www.mongodb.org"
    1 }( K" Y" G, t. T1 u4 L
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} $ E( N7 [& a* T8 D& h
  3. , response_time: 0.05
    4 S# A( _0 k; U' f" e7 f: C
  4. , http_action: "GET /display/DOCS/Aggregation"
    % W7 P+ k: q9 G# k* J- ?9 c
  5. }
复制代码

3 c/ K- W. |' W. u; k使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; . L1 b7 V& Y9 u: L0 f
  1. db.test.group(
    - M* G  n; x+ L% y2 F1 t- o
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    6 @/ h5 A* Y* G  K
  3. , key: {http_action: true} 8 _$ G( s4 q& P2 j# e, I, d
  4. , initial: {count: 0, total_time:0}
    % t! O7 p0 i9 l4 j
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    . @; y( ]! v4 J$ [( v
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } # k% Z$ o& ]( S' ]( r
  7. } );
    " T! q. y% |4 |. i$ P6 e+ g& P1 k

  8. ; o$ \( P1 L$ I& @3 d
  9. [ $ i4 U* c4 t( z) r( t. D
  10. { # r. |' \$ ]7 R$ p3 R( W; r
  11. "http_action" : "GET /display/DOCS/Aggregation", ; L* E; H7 m1 X* X9 c0 o9 o- D
  12. "count" : 1, " t  Y- m" f1 p0 z3 S  E$ z0 L' ?" D
  13. "total_time" : 0.05, , y7 T  T1 R3 C
  14. "avg_time" : 0.05
    6 @2 J  R% e+ y4 {; C: W( ?! t
  15. } 9 E& T8 v. X$ Q& A3 O) W) R1 q7 F
  16. ]
复制代码
& d" m1 b0 V* h
( P5 }3 w) k, Y5 Y- _

% \* W9 W7 f1 A) gMongoDB 高级聚合查询
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% Z3 o& a8 D* u6 l. {% v
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
7 s& _% n2 C( i1 _
3 x* L5 n  N( b4 ^9 |5 @

; N/ C1 l* q5 @; f, R' S) O
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    1 q- U  U6 b6 l
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码

% A7 E+ M3 ~7 H; q6 r) j6 K3 X* L$ s  Y! I
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

: v2 B' L1 p3 x8 k5 I0 d3 l3 S9 P) \& B. Q6 _) b
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

$ Q- Z8 j9 r5 E( I
% `: E6 A5 I( o4 j4 M# F
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

. R3 b  C5 N! U0 I
: j  ]' z2 _. t) M! D- F  Q4 m: i5 [
输出如:
  1.         
    : R. w, d, N; y/ g, Z
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
6 |. G7 }& j( H1 T! K, h1 l5 z6 L

& Z: J  Y9 B1 ?2 g) [: X. S5 ?
4 w$ R7 ]% z0 i% V, ]! M
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    / w) ?9 S6 R$ q! y
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    / \* D& B0 @+ h: ]& P5 b
  3.        xmlns:context="http://www.springframework.org/schema/context"' N0 w$ U( C" d  _
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    5 y( {9 T; U9 A$ v
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    : k9 _4 v, F: l# W
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    9 `/ h7 W6 ]) Z7 ?$ V/ V3 ^1 e* Y
  7.           http://www.springframework.org/schema/context; T$ i% h, b! R/ G
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    + u: s5 ~1 C/ m& v
  9.           http://www.springframework.org/schema/data/mongo
    $ W9 V* W5 h/ z; j( Z2 S8 F' c
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">/ J3 |" S, {1 ~, Z, e! x/ g9 X
  11. , b8 r" m+ W7 c1 R9 X
  12.     <context:property-placeholder location="classpath:mongo.properties" />1 d: ]  t: z$ ?

  13. ' N4 \4 f: n# ^7 O: ?8 C$ K
  14.     <!-- Default bean name is 'mongo' -->' U$ D/ W3 s1 l* _& ]" J
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />- x$ _. L' ]" t& H6 F2 d

  16. 4 K6 ^( ]$ l% J# e
  17.     <mongo:db-factory id="mongoDbFactory", E& J2 V- F: e/ w1 C: x7 k
  18.                   mongo-ref="mongo"
    5 o- A+ A. `+ p
  19.                   dbname="mongotest" />4 T+ s0 e9 m; `0 G) y

  20. 8 \: J9 w( o# s: `
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    $ k3 G7 y0 B3 ?* M4 r3 W4 T
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>! G/ I8 i$ h) z% e& A1 L: u
  23.     </bean>  b+ J6 P, v2 \* A. V) f
  24. </beans>
复制代码
3 ^" D* r5 S+ |  _
; w* O- ~3 K' h! e: r( k
maxmin的测试
  1. @Test
    : k5 w& k1 ]4 N; `; T% \& g8 L  d
  2.     public void testMaxAndMinAge() throws Exception {
    . y, G1 C, v4 S) h9 C+ w* H4 Z9 M$ X
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    4 c/ p) M: ^$ P7 U
  4.         Person result = mongoTemplate.findOne(q, Person.class);" p) |/ |" S9 [/ c
  5.         log.info(result);
      y. I$ w8 t4 r6 ?' A
  6. + ?' p( ^5 C, \2 e) t1 T8 }
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);2 z! C: R) J/ |6 P
  8.         result = mongoTemplate.findOne(q, Person.class);
    " l$ M+ b5 x8 L/ v# i
  9.         log.info(result);1 l8 o- @8 b  K! r; x* k, n) w0 c
  10.     }
复制代码
3 t; E6 n5 k0 X3 O' A! ^9 f; n! o
5 W3 X) i$ T4 O- ^4 E, H( o$ V
distinct的测试:
  1. @Test
    5 _* A) `1 Q; X
  2.     public void testDistinct() throws Exception {
    # r7 s4 D/ j0 @2 B: w, @; E
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    : k; X% g8 ?$ O# B3 O" r- G
  4.         for (Object o : result) {
    & A7 T& G7 Y- e# J$ h
  5.             log.info(o);' i0 Z8 W( l. Y6 t* Z" ]( N; L5 W9 A0 c
  6.         }6 y  \% u: D  \- E7 Z+ H
  7. + M6 O& [8 S' `. y( C- ?1 Q6 F9 |
  8.         log.info("==================================================================");: `' p# h, i' e$ r) a
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));6 L5 N8 k/ g: l" U' u: y/ ?
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());3 P8 i2 H% i! W  x
  11.         for (Object o : result) {
    4 s7 j! H1 o8 P6 l9 N
  12.             log.info(o);
    + x7 o' h: N7 L$ Z% s$ @3 K
  13.         }
    ; K. @$ Q4 m% q+ s) M! K

  14. 8 s: F) {: y% c3 O/ T; S
  15.         log.info("==================================================================");" T) A) C7 j& q8 S2 @
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    ! T8 B& a7 s! X
  17.         for (Object o : result) {( x5 R; O* P  }1 v4 U
  18.             log.info(o);+ l- G% g" v" B) j
  19.         }
    9 C4 |+ z- x: D9 E% d
  20.     }
复制代码
$ l* i% F  s/ c% r1 z, l$ z3 n
5 r: n' @( N7 t2 p
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    ( R. I, m! q: @' {8 C6 B/ q
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    ; d4 N$ T) ?7 i+ S
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567897 V9 z, k) k, c; K
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    9 R- G, C+ Y. _4 U% i/ K4 i+ v
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni! g3 y6 a5 J& q, x; X
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    # i8 P: g! P9 r  U' ~! z
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    - C+ a) A6 a9 _; H3 j6 N2 V
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================: @8 ?/ f8 r' N" [' f4 r8 B* V; D
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    / ^$ i/ O; Z$ Y: R+ R8 `) j
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 3456784 o9 }2 y' Z) u9 J- {4 q2 t
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    , h0 G1 X& b5 A
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876545 P, ^. r* i& q2 s
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================. k1 k2 ?. m0 i# w
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa% T, ^1 D2 r" z- {, ]: T6 ^7 _* f
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb5 m3 x% T( @. C3 x1 ?, T- I4 m& V
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    ( W/ P) ]6 K+ N9 x3 E0 Q& |
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www) R$ s8 G% r) r. z- p& {$ H
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    : W4 s% N3 b' p$ P( D3 k* m$ x! _
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    % W" L+ C% O: ~+ F' l6 f. l
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz1 a4 ~8 P) s* z5 y% f4 d" d. I4 w3 R
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr. B+ \3 c/ I! N3 {0 l
  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
复制代码

! b9 E; W( z. e' B+ |/ p5 E* p$ j' q& q
这里我要特别说明一下, 当使用了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等信息。
1 v! W; _3 `0 c
  o" q7 ~0 ]* Q% q
) R# e$ u7 ]5 A- u' q6 Z% @; N
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-9-21 03:13 , Processed in 0.065484 second(s), 22 queries .

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