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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
* w1 _% x9 a/ P' F3 ^$ |4 s7 b# x$ [# b
1 ) . 大于,小于,大于或等于,小于或等于
( O' g- J$ U" V9 w& y2 J) e
9 s! G. P# J3 v# z! f$gt:大于
! O  |  C! o! m# A* b; H% b* n2 q$lt:小于
- \2 E$ R" f+ M  m4 D) M0 Q' E$gte:大于或等于
0 L/ x- O. c8 ], t$ m4 `# q8 \: S$lte:小于或等于
3 y" y4 M8 N6 U+ {5 k5 @& t% L" e/ K" r0 N' r! x6 @
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value. j6 d3 T3 h& o9 |( A: J  U) q2 |  u& @& X
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value& s6 ^3 W" H5 O2 r: a& F
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value% Y9 P( I0 e9 `9 K) l; B, }' r
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

5 U7 \4 n- X$ V- {1 A& c
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    # |/ U1 ~" X+ S, e3 \
  2. db.things.find({j : {$gte: 4}});
复制代码
) ^, ]+ H. _& }! U0 ?/ B+ h) P
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
" d4 Q* ]. n; e. j
6 Q2 s) O2 t3 r" g7 M

2 j! ^1 K0 }2 t2 o7 W: Y3 k' B
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
- F0 A; f/ x4 s4 P- u- T) Y# X
3) in 和 not in ($in $nin)
3 B; C9 k2 i; a& c, t/ V; |! F1 @6 b, |  q
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
3 I5 ?  p( ?) R* ?0 D3 M  L" F( T* H
例子:
  1. db.things.find({j:{$in: [2,4,6]}});7 y7 a) L* G  K* d7 i8 ~- V. _
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
* a) |+ x  [# b6 H7 T  j* Y

2 f+ K( R. O# Q# A+ p: W4) 取模运算$mod
" ~) c8 P% I( i1 W) P. V/ r, Q6 ~. Z" D- e0 s/ b
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
4 K$ V6 Q& [; H+ Y1 j
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
9 n7 A+ R3 y! K1 S7 I% B6 N

. R* Q* E. n$ V1 z9 j) J5 }5)  $all
0 A* h1 A6 u1 z, ^8 ]& k  X" x: H  i( m  o1 j
$all和$in类似,但是他需要匹配条件内所有的值:
: A3 K% H; K$ f& m) X. V' k! T
: X! m) N' f) s- \+ T# C如有一个对象:& k- M7 A+ R' p2 u, [- P# b) G
  1. { a: [ 1, 2, 3 ] }
复制代码

8 ?/ v+ j3 G, a' j' r. u9 o- K
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
) G+ b) j# ], \0 V7 n3 \  c
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

1 e1 S, N: C9 d- \
( b$ |9 ]8 ^: V
6)  $size1 z1 n1 c  R( T3 {

/ \5 i! u% i( Y( K$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:1 B7 H3 R, A) k& L5 @4 z

4 E! P- h; b- I! K下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
4 S. V9 r8 P3 _, V4 [, V
官网上说不能用来匹配一个范围内的元素,如果想找$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.
1 C% r% g4 _( R6 g3 U1 j5 P
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    % h! X$ ^/ V; O- H3 S$ s
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
! z0 @  T! \, c, h+ F
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    ! O" ~) ~7 ]; \( A) a
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
  y2 M. H$ r5 b8 Q( t, |% T
9)正则表达式, L1 ?2 |; L! v' r
, r: D1 I3 y1 T6 i
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
" b3 B  L; c7 X2 N* w
10)  查询数据内的值
1 m: m# w, B& V$ c' s$ D) k4 {/ N! B" W# u" W8 K1 p
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
7 g# _- s+ b/ @% ~8 [
11) $elemMatch0 K) [  c% H. R; _, s

9 {# S0 N9 d( y, b4 `# q如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
      o  F% u7 G& E" ?4 P8 B
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  7 j: Q: {( ?: d# Q9 A9 ~
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]% Z! ?4 [7 x* k1 ?$ Y0 H
  4. }
复制代码
- X9 r  b" ^" c" Y
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
: ?; i7 l5 u: p& G' @( Q
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
* k9 u# d& g+ @0 t1 E
4 ?- ~0 a" c" x1 F; F12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

# O3 _9 u) a# ~' K
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

" @! b' [0 K" t" G2 \) i
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

- Q& l% R3 {8 M: L* t- I5 h
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

  U( q: m6 v' N* D/ P
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

. u8 N( Q/ r% j3 k3 ?; j/ \# R
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
% x& }5 p  B" i% ]! A
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );7 f' z0 k$ a0 j$ o# D- R/ P
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
* Z$ z0 D5 U& n9 r9 L& o
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
, [1 }" M" ]) P, H. `$ W! y
- v6 ^5 R7 z4 s6 O7 [! _. vmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
/ j! U2 I2 Z. ^0 ]. `0 Z7 B& L& m( Q
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
) C+ l  x" y4 d6 Z9 _. B( ?4 S0 q) I- X! y- G: e
版本二:
" C) A5 w1 i8 m6 e. @
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
4 e( y( m; [7 N  }- _1 e
  1. use admin
复制代码
, F6 Q1 ?6 G5 b6 o3 D7 L
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

8 ~0 E' r0 d1 K( A. E4 A0 S" c" q
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

! e( g& \4 ]( `, Q" E0 }
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
' F- @1 v# s: n$ Q
         5. #删除用户
  1.           db.removeUser('name')
复制代码

" n( _# [9 O. b3 C5 p' |+ L4 C# t
         6. #查看所有用户
  1.           show users
复制代码
. q# H2 v3 p% a; f8 W" v# _
         7. #查看所有数据库
  1.           show dbs
复制代码
# V5 ]% q3 M* k4 N- Q
         8. #查看所有的collection
  1.           show collections
复制代码
( H+ X- z) `) ~6 ]% \
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
% \) i# Y* P5 Y6 i2 d' v$ ^3 y+ N
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
- c) F8 S" Z) S; D3 {- G+ O
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

1 z) y5 Y! w9 @# _
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

4 O! ~4 U1 D! n
        13. #查看profiling
  1.           show profile
复制代码
7 p' a- q% ^: v
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
- t# b! h, u% j; @
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

3 n. K% r9 J. ?' m0 @
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

8 M1 B7 V. N- \. b+ o$ w# o
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

9 k# `# e# e$ F% t4 o8 u
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
& p2 q0 h/ ?% n# O$ s
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

$ b0 ^" x! i& o* Z( D
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

) _( E& C+ R' O0 @  y8 F
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

' }: ?/ Y' Z' ^5 C, H  o1 U
   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()

; c+ `) M* N( B. a
6.  高级查询
条件操作符 : c% X5 o4 l1 d" U; M: d  V. e: S- n" b3 L
  1. $gt : >
    # z6 a" w* P- y% x* M9 x0 x5 u0 \5 f, X
  2. $lt : < . S1 ~% j( J" @$ A! U
  3. $gte: >=
    $ C3 T# W% u" M( r) \
  4. $lte: <= / v* U, ]2 R; q' t/ F, U/ V
  5. $ne : !=、<>
    ! t; }) w9 I9 y- e
  6. $in : in 0 n# w- O: m' ]
  7. $nin: not in
    % m) H) r# }" m- \# f
  8. $all: all
    - \  |* F9 C/ P$ I" m& M" a8 K& r
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
. S( A" k; e  S% s
; t$ e) q* A( D$ p4 j! [
查询 name <> "bruce" and age >= 18 的数据 4 Z; L0 n5 O6 i2 |2 C, J0 x
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
! p7 E6 E! D6 k( A  s4 W4 g
7 w. Q+ w4 H: `, B
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
( u8 D2 ]; q5 _) @
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

5 w8 g( B$ V- ^- A; E1 u2 Q* g5 ]8 `% q; z& R
查询 age in (20,22,24,26) 的数据
: [0 n) l! H8 g  o  O; `
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
( h* d2 j' ]) G1 b$ Y7 Y8 T
5 q: p, _  }! I# i
查询 age取模10等于0 的数据 % I+ D( W$ I+ S2 m7 [4 r' L
  1. db.users.find('this.age % 10 == 0');
复制代码
- V/ z5 w+ f0 K: O/ {
或者
, A& }6 L3 |1 [8 L
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

0 E, t  S0 N# o  _" J
9 q. v. V! U  z+ z3 j+ k! F匹配所有
. y" j' }/ g/ b) P+ a, y2 t& Y
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% e9 ?! K* M; E  l' X  }
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
0 z( L2 D& f/ i4 ]7 p可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
0 H$ J9 l. e) }( b$ u) R* [6 S) D5 c. E9 A( m3 w* {
查询不匹配name=B*带头的记录 * C" P$ l/ a' P/ s
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
5 Q- c  T: u) \. j4 ~
查询 age取模10不等于0 的数据
# e3 E" H6 A* K( h* C
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
; X; G  W) y0 ?! s* R+ X
+ P* ]( p! ~  O2 z
#返回部分字段
1 b# v. p7 w( L1 Y2 q. H选择返回age和_id字段(_id字段总是会被返回)
1 o# @, b( Y7 T# H) q6 w& f
  1. db.users.find({}, {age:1}); 3 D4 B; N4 I) ~0 J2 p2 F# V
  2. db.users.find({}, {age:3});
    2 S# w/ Z# Z% @3 n8 T: v
  3. db.users.find({}, {age:true}); 4 F& f  A& u$ b0 i
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

- d" k& y- X( A+ J2 v0为false, 非0为true
# ~, m7 ~! L' L# y) f) S; m- C) R; _6 P! s( n  m# m, t0 G9 o/ U
选择返回age、address和_id字段 ! B7 g2 X9 @4 i- h4 k# h- F3 ]
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

' H7 Z0 P' O8 c4 X1 ~% Z4 z$ l5 H, Y: R. B$ s' e# O; V5 p
排除返回age、address和_id字段
; y2 @! V/ o( Q6 L
  1. db.users.find({}, {age:0, address:false}); $ M" S7 E1 }) c3 L
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
' x3 a. \$ [  x1 \: J4 }! D* K7 e/ b
4 v" r  E* G9 ?. S' e7 y+ T& o
数组元素个数判断 - i+ u) @! _' F* z  s
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
+ L+ O& E+ u. y  ?匹配db.users.find({favorite_number: {$size: 3}});
4 V- _& q% `  \! P2 s4 h2 p+ A不匹配db.users.find({favorite_number: {$size: 2}}); 0 W  {" n& V8 b- k( G, u
- p! k: ]# C- A3 L$ E* n
$exists判断字段是否存在 $ r8 h- y; l- p: S/ J  _
查询所有存在name字段的记录 % l4 i6 L* S  E' u$ L7 x. ~* I
  1. db.users.find({name: {$exists: true}});
复制代码
* y/ R' A4 L& H$ w9 c
查询所有不存在phone字段的记录
% X/ ]* c& S- |* [) O
  1. db.users.find({phone: {$exists: false}});
复制代码

; t' A. e# h% P' e" g" f! ~" M/ I9 G, J: F6 T" O( ?
$type判断字段类型 # s, m$ l0 r# f% P$ Y& m
查询所有name字段是字符类型的 / f& C! v; V0 W
  1. db.users.find({name: {$type: 2}}); ! l7 g3 d0 N3 l4 G
复制代码
. V3 B' w: I0 g' Z! `% z
查询所有age字段是整型的 2 F- S' i8 V; H
  1. db.users.find({age: {$type: 16}});
    # l5 q0 p* M. y
复制代码
) r6 y5 P, d5 Z5 I
对于字符字段,可以使用正则表达式
1 E4 T$ N5 _% M- N* @查询以字母b或者B带头的所有记录
; V* `9 B& N/ R7 L% r9 q8 B
  1. db.users.find({name: /^b.*/i}); " ^9 R; V& f% H1 f
复制代码

/ E! W! M$ K) M$elemMatch(1.3.1及以上版本)
2 Q) Y. M! G5 p为数组的字段中匹配其中某个元素 , j6 l1 Q# C: |5 u# d

- M+ ?7 H) m1 a/ E* j) oJavascript查询和$where查询   S. _# N0 m+ R. T3 O. h
查询 age > 18 的记录,以下查询都一样 ( N1 w9 o; n! n3 ]7 V3 F
  1. db.users.find({age: {$gt: 18}}); " p3 t% k8 T& ?6 C- u! N$ ]4 n( m
  2. db.users.find({$where: "this.age > 18"});
    9 Y; I7 G! L  A9 S0 {, E
  3. db.users.find("this.age > 18"); 9 h$ n+ T, ]! ^( t  T/ G- P
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
+ x: P, [- {; E5 e7 F$ L; p
! e1 V+ g9 T! L
排序sort() 2 `! X  j% b5 l" b
以年龄升序asc . A; I; U) j4 V7 K% H. F
  1. db.users.find().sort({age: 1});
      ]+ H4 @# W+ ?, U3 r
复制代码
5 _) B$ M6 v' P. N
以年龄降序desc 8 V) s! w' j' R4 M1 d; d4 c( n
  1. db.users.find().sort({age: -1}); ! n3 _. q6 q$ A, Z1 b# i6 z
复制代码

. S. o, N5 s3 @- n. Y3 G限制返回记录数量limit() . n' e: b7 w3 v, L
返回5条记录
9 D: x0 t7 x5 J
  1. db.users.find().limit(5);
    + d" B) Y2 L* o$ i' b
复制代码

6 t0 c" j/ j  x; j, U  n+ Y返回3条记录并打印信息 * O1 z# c, f7 [
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 8 B4 Z) {- ]1 y' q9 o
复制代码
& f$ T+ ?. k4 E. H9 y% Z
结果 8 b7 E- v6 A- Z3 ], _' j" N8 X
  1. my age is 18
    * g, B$ n# v5 N, k* `- R; z0 v
  2. my age is 19 1 y* }! }; a) a' l0 l
  3. my age is 20
复制代码

; R( Q( a4 K& t9 [: j* \# s
% z8 D( G, r3 l; z限制返回记录的开始点skip() 2 }( }9 l9 _) Y) }
从第3条记录开始,返回5条记录(limit 3, 5)
- j, e; j3 ~" s8 H. K. K% L
  1. db.users.find().skip(3).limit(5); $ Q" m% s6 Q$ I; J
复制代码
7 C' M+ r0 \$ w  [5 _/ C6 w' [
查询记录条数count()
; O% }5 j, C3 s& A- j* b3 h1 t1 z& I' sdb.users.find().count();
# a$ b( o3 E' {db.users.find({age:18}).count(); & x7 B" u( x  @  g" D; ^* P
以下返回的不是5,而是user表中所有的记录数量 ! u( \* V3 f5 Z# m
db.users.find().skip(10).limit(5).count();
. R* h! C6 r1 ]  @0 g如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
' E% B2 V. p9 ~  g6 X$ E" Z
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
; A% E& ?) x; y
1 u5 _6 j) T1 {. u
分组group()
6 A2 k- s% }' y: M2 q假设test表只有以下一条数据 ! M% N2 v* o+ e* h! ~7 ?! b- V
  1. { domain: "www.mongodb.org"
    8 e$ o5 F1 O3 U& P6 p9 P" n
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ' K/ y' a. r& G/ o/ q
  3. , response_time: 0.05
    : k7 S" K9 |9 u
  4. , http_action: "GET /display/DOCS/Aggregation"
    2 c: k3 |0 D6 ]
  5. }
复制代码
) v- q8 O  a5 J8 `1 {% O
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; " J9 j9 }& c; b
  1. db.test.group(
    ( R3 ~  R5 \# H
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    8 o9 Q' C" Z2 ^+ X# i: u. l/ G: f
  3. , key: {http_action: true}
    5 u- i' G/ Y8 Q- i8 N+ w7 J- [
  4. , initial: {count: 0, total_time:0}   e0 _% m! r; j: A! W! E
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } ( z) I7 n( C3 r* G; z0 S) Z8 ^
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    : k2 M% t0 z0 r% B2 h
  7. } ); / ?$ c. o0 y3 P$ S" Y6 R$ d

  8. * R9 W" A, U1 i9 k& @4 ^& f
  9. [
    / c( D! w% f. n- X4 m
  10. {
    ; y! p4 C! M- z1 x: U) k: D
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ( n) c2 K. ~9 {
  12. "count" : 1,
    , b; i0 D# ~6 Z( N
  13. "total_time" : 0.05,
    % z. z/ N# R4 u( }
  14. "avg_time" : 0.05
    3 w( p2 N" P1 j" t
  15. }
    / _. M9 U9 O2 m2 @/ C2 P
  16. ]
复制代码

' M. Q' Y. j% Y# z/ K$ {) }: d( o
$ _. C3 T" L* d# `: }9 K: B
" e5 r+ h3 _* g  E: \2 {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 和Min9 n0 g+ S/ P% }5 w) ~
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
6 H8 ]' H; {( G  ?

. L9 C1 d) y: B4 j, b5 V& G/ `& g
) Q9 h9 z" [; p; X
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    2 H! q4 _7 d6 t1 o
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
( I3 S) k" c  D( X+ y9 `0 P1 z

5 b5 \5 V! F9 B" n0 `5 a4 t
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
6 q! c/ _5 E, M" ]+ a! F
6 \0 I. j  j; A8 v" r
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
3 c: N. j& y5 Y7 T$ D  `
) y' j) C" Y. I
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

8 x% e! J9 ?  r1 p0 t- s+ ]" f2 J$ \+ Q+ c: W5 o3 m
输出如:
  1.         
    3 J, `! d1 k0 J4 M: m' P
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
1 U0 M9 H8 @. e+ h: e

. B5 _  H9 |. m( N5 a9 W* S+ u, n  e5 k4 D7 \4 g1 @
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"5 H2 W5 q; Y5 Q2 C
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    , _1 _# A2 r+ Q0 b* g- j8 S
  3.        xmlns:context="http://www.springframework.org/schema/context", Y% |% v5 N' C2 b
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"/ j/ I& G9 P8 x+ l% d2 h, V
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans  v! f, G( @: L/ D
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    2 L7 r& O6 D; O( l
  7.           http://www.springframework.org/schema/context
    % y2 [. `2 v5 `4 W
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd2 i8 S( }1 d& R( S# \4 g
  9.           http://www.springframework.org/schema/data/mongo
    $ h& P% P$ i! A/ V
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    ) g9 l9 U% ]! E8 K
  11. 1 y: N. w, U4 n, y! ]4 K; [
  12.     <context:property-placeholder location="classpath:mongo.properties" />; }; j' z. d2 @5 U8 d$ p
  13. , q# h7 K$ M7 _$ o/ X- }, f3 p' t3 s
  14.     <!-- Default bean name is 'mongo' -->. I( _4 }0 ?3 Z/ E% b- @
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />. p/ F. ^& x$ b  I/ x& X& B: Q
  16. " S# M$ t% @. {$ G" `# f( S
  17.     <mongo:db-factory id="mongoDbFactory"
    - a$ t6 q4 B5 F; b' \1 X4 C
  18.                   mongo-ref="mongo"  y! n, \1 N* S; v. {6 Z7 V
  19.                   dbname="mongotest" />3 M3 l1 [) l5 G* {* z7 w
  20. . d5 }& x+ q5 J- P* P! E7 k
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">" ~6 S: N" j7 U. b9 t
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
      P$ l5 E, I: g- V3 i4 R# g9 J, I& y1 }
  23.     </bean>, R2 o" ]' g8 e* _+ x  z! W
  24. </beans>
复制代码

5 j7 a' p$ \: ]* a
2 w% v0 B& q5 d- A0 v* B. l- }$ k; K
maxmin的测试
  1. @Test
      m# e/ _! a8 m- g7 B8 M; \
  2.     public void testMaxAndMinAge() throws Exception {" T1 k. }3 q( B" u- O* j
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    3 v) X+ q1 ]7 S( C, J7 a
  4.         Person result = mongoTemplate.findOne(q, Person.class);* h# E' F, A/ t" o
  5.         log.info(result);
    " ~/ A3 l/ @. K
  6. # Q& n- o* P) T1 _
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
      ~9 x: k, }: [  d  q6 }1 D
  8.         result = mongoTemplate.findOne(q, Person.class);
    # L3 l' ~6 V' T$ M* h
  9.         log.info(result);
    . E5 u3 L+ }: m0 Q
  10.     }
复制代码

0 k- ?0 I# \- @2 c' J* l; P8 F! p6 t: Z3 K5 z* {
distinct的测试:
  1. @Test- [0 T* j( f/ f) w
  2.     public void testDistinct() throws Exception {; L/ ^* g( T, O$ _- b6 z8 b
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    7 N- @9 F. n8 k: A" ]$ {+ `
  4.         for (Object o : result) {
    4 g* n# V1 I2 L
  5.             log.info(o);
    6 p2 a2 _) `& F  K0 B/ |
  6.         }8 g; K, m( [& r" ^
  7. ! w& v# K& Q' ^5 H/ O  E
  8.         log.info("==================================================================");
    0 q& j# x9 j) e2 k2 M
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    ; {& F% m$ t/ O- S; a
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    ) ~( B) I$ o' R5 K% O# t
  11.         for (Object o : result) {
    7 {& U$ M! _. a" k* f) [% I
  12.             log.info(o);0 y# ~! n& }& W! b" m
  13.         }: m( [5 j' C& B( n6 U- l

  14. + C" c# b, @. U7 h$ A7 G" n
  15.         log.info("==================================================================");' O$ S8 A. k0 {
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    / C8 T6 ]" A4 }
  17.         for (Object o : result) {
    : f1 \+ l7 J3 R$ a* z
  18.             log.info(o);
    ( k5 C$ k4 M1 G$ r" D- f( u( ~% B
  19.         }
    / e, Y7 K0 F# M/ |
  20.     }
复制代码

& n$ i4 S  z( {; X4 A% M, j4 _3 v1 C6 Y0 ?* W* S: k# x: P+ i5 S7 I
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    7 Z) h  q6 f+ i2 y, [, {7 C' S
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    * R& @/ h  c8 F2 o" F8 a
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    * W/ h7 v' v5 H6 W: r# ~
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    1 z: N$ X& a# K+ B6 z2 C# ~7 e
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni! I# ~; s' c) P
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo( M# ]3 {5 |6 a5 X1 ~
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    + Q; m1 p$ ~( r9 P( m
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    # ]1 S5 I8 t8 e" g' y
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 2345679 V( p! {/ F5 n4 r
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    : i6 s. t! d& j; v4 `0 t4 ]
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789# E9 f# b& H9 A6 P5 R+ n
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    1 j: d0 ~( v1 j- W
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================( b! _- E! [+ h2 f$ R
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa6 ]; `; n+ W) P) O2 f6 ^9 s
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    ! s7 P4 W8 g6 S. k
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc+ I: O( y/ U0 x) R$ D2 \
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www; l; F6 l" [% {5 _# o
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    ' A" N* l! }% f& Y
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy: n) f" ]- |3 `. ?& P4 \
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    ( X4 e9 m. l, [0 M" U: _
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    : @$ W. Z% V8 J/ B  B' O" J
  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
复制代码
) g3 T: I4 i+ h6 t/ n6 ~9 I

0 `$ A: t& D) F, ~2 w* U8 A, [
这里我要特别说明一下, 当使用了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等信息。
! p' Z2 D# W2 @) T
- s* P1 U6 q2 v9 t6 U0 V
( I* ^0 J: L& ]* R; p1 b) T
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:58 , Processed in 0.163711 second(s), 23 queries .

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