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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
! v+ k) S" X  G! Z: ?1 s+ g, t% m+ }
1 ) . 大于,小于,大于或等于,小于或等于$ ~& R) V' r; C2 a) N& F
0 `8 I) w: w2 \6 U
$gt:大于: P6 y1 F& }1 w
$lt:小于
+ W( @; c+ N9 J4 }6 S$gte:大于或等于
* g/ G$ i) U3 c2 Y* m$lte:小于或等于
* N5 j8 y9 G6 F4 G7 a% ~2 a* a* l" P1 ?; {! l9 ?
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    ' V; g$ Y2 X- r4 w! e
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    2 `7 S' e, @1 n/ o: E1 u
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value( o2 P7 J0 }! l5 |! ^1 Q1 {- [
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

- h# x. u) z0 W/ Y* N
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    $ s* S! L7 O" X2 ?# X  {) ]
  2. db.things.find({j : {$gte: 4}});
复制代码
1 i) `3 f) f2 n4 c& K1 A
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

" j$ o- G9 Y0 I# C# i. a) x# h+ Y5 R6 Q) [
5 u6 u. v3 [' m
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
/ D$ f/ {; |, v3 L) J
3) in 和 not in ($in $nin)
1 E; w/ E) g2 [: k/ c6 Z2 V/ q0 I1 h7 V& l8 u
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

$ A2 M' x! S. X8 M/ V3 K
例子:
  1. db.things.find({j:{$in: [2,4,6]}});+ ]) k. X2 |9 ]. A
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
  Z, n( {+ T' g' Q8 m2 W

; S% O2 t0 U8 y, l8 E* X4) 取模运算$mod' Y# I. |' v/ ^& @& s; U& h

& s  X3 f, I' E( M如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

* p' z  E2 e: f7 A4 \, v4 z) h/ P( c2 ]
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
8 f# W+ f/ l) O" t* x8 D% \/ u& b; D

6 D# u/ I1 A" d1 o7 }2 K4 d5)  $all
( l; t2 [+ m; i; V: V( ]7 b" F
1 ~6 F8 j3 U. J; d$all和$in类似,但是他需要匹配条件内所有的值:, U! M, a  H; W- K8 Z
6 N) S5 U5 U( Z9 U7 U4 C1 B+ ]
如有一个对象:
! S. B' ?) [/ l: H
  1. { a: [ 1, 2, 3 ] }
复制代码
! j4 k$ [/ I9 O+ J% o2 ]( i
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

8 y! D% |( i! v4 F( {# ?
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

, j, i4 I: `+ Q# \& v& J

4 e& q% W1 a- b! R. x- M6)  $size, M$ J/ j1 O0 m( e" O

/ o: y& n. ^# k( Z: R$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:4 l, g' L& }& M( l
; Y- w4 O3 j- o4 _! g' r1 ~
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
4 i% w2 k; q/ ]# l' t# _7 N
官网上说不能用来匹配一个范围内的元素,如果想找$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.
9 x( C: t# z  w9 p$ V: j% V, |
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    3 f% G% h5 K3 u+ n4 a9 }# B
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

( B3 k5 }  K* w
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string9 W  }- B# ]  ^: `4 k# G
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
  T; G) @6 s5 [* U! R* P# I
9)正则表达式
- L% A% O4 i& ?" I9 H- w  r1 p  r" L, b
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

4 W$ C/ v; ^2 V1 U
10)  查询数据内的值' U4 c1 u" o: g0 O' X& {" [6 ?
& m' e/ Z+ R  I2 @) P7 r6 y
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

8 R6 B) i& U% ]/ r' g! J
11) $elemMatch
8 Z2 g) b% h7 \: d; |3 R/ ?6 B$ Y
- g/ P" s$ W7 N$ d( [/ |/ t  y如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    3 r2 C) o3 e6 E% h* M) ^
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    + t: {) f( s9 r4 O7 J( [8 R
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]3 M4 w7 [. g( b" H9 x
  4. }
复制代码
1 |9 _. ^+ Z6 y+ u5 ]
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
1 n7 @9 [/ i/ G' a- {4 j' ]6 E# T: Y
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
6 I% I9 s0 K& q6 @1 J7 C4 o6 K& l1 K% W
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
4 r5 Q' w6 x0 a5 B0 U$ p: k  d( W
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
8 }5 E  Z1 }0 ?0 s
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
: Q5 k  w& D, l/ Z8 P7 H
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

7 A( P; _2 p$ I/ j  \; b
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

% g2 J/ G9 n* B$ f+ b
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

( ~" b4 L, D0 j+ U1 f
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );0 _0 M7 H; Q7 g7 {7 T
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

' z) s+ _8 D/ ^) s
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
% ?+ N. `9 n5 Q
: j- O0 z7 M& Bmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
) [; B- I, P" m' y# V+ d
& W4 ?2 Q, r% |3 c5 u6 s! hhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
/ U$ e+ X. a* v! a8 m5 L
8 S$ v' W+ J" R) _9 H+ i; N版本二:, i. `5 f! U& s
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

" P/ l. N) f. B# x3 z
  1. use admin
复制代码

$ M2 a% S" H% z5 J, a1 u
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

9 i* E9 }! j3 o' }8 w8 P. B% h; |
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

/ e" U; d- N5 F) u5 \6 J. [
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
( ^! U5 d* k, y
         5. #删除用户
  1.           db.removeUser('name')
复制代码
( K' \# Z0 d( R! n4 m# }+ l
         6. #查看所有用户
  1.           show users
复制代码
5 q! t, `6 I- ?/ C
         7. #查看所有数据库
  1.           show dbs
复制代码

% ]9 {8 _' \8 B2 H
         8. #查看所有的collection
  1.           show collections
复制代码

1 s; l6 ?# _+ j. u# [: F5 ?1 j
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
( u; {+ r$ o- m1 t' [8 a7 w
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
9 |' J. j( d2 m3 Y+ l) b
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
* d3 ?/ m' \8 O9 c  D5 ^' {
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
" y1 U, }" ^: `( R5 d: o$ _% k( G
        13. #查看profiling
  1.           show profile
复制代码

/ p% F4 x5 }+ z4 i2 V
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
( |0 p; a- `9 G& k2 g4 C
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

+ g( H4 n. j' a- M2 O# Y: S
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

! y( B4 M0 D/ D1 O
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
8 ^% h8 e& L  g
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
7 K; T3 J; Y8 R3 E; [$ \
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

  l$ a$ M, E% ~0 ~% j6 k
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
' _0 S8 X) n: e  j3 z  J
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
4 K( ?! I( x+ D) ^0 U2 `. p
   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()

; B8 D0 r% n) ?6 @4 B) |9 M
6.  高级查询
条件操作符 - @, t2 u) f: _6 t0 h2 [) h
  1. $gt : >
    * w; V/ x7 T: v+ X# F
  2. $lt : <
    9 L- o; C4 N8 x5 P9 F. e7 H9 K
  3. $gte: >=
    ( \( g# @3 b* s! Q$ \# L
  4. $lte: <= 8 W: t8 v) x) S( O1 I
  5. $ne : !=、<>
    ! p9 \6 ]/ ]( U5 Q6 s
  6. $in : in , C, m$ d3 t4 z) o
  7. $nin: not in : j' w7 T9 ~1 z1 L+ p
  8. $all: all . F7 }1 q* s& Z% I
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

0 J. m5 i. |+ G# U' z. p+ H$ i- _/ w) U- b4 J* _
查询 name <> "bruce" and age >= 18 的数据   `1 U* B  U) R
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
6 Z8 u- _/ i7 p( b( o
! b1 x7 E( Q! y% R
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 & Z2 ]* F7 e% H) E/ Y! Q* \  y, W0 J
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

+ E6 a5 h2 @* r6 b+ ]0 ]3 m! h7 N
: g: [' M4 z: \查询 age in (20,22,24,26) 的数据 * i% G8 E/ o- C* D5 X
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
5 h& D$ {. f5 w0 L
& |+ y' [& ~+ C3 S1 f- f
查询 age取模10等于0 的数据
) Q) A# `3 x" \" P5 C9 ^/ B
  1. db.users.find('this.age % 10 == 0');
复制代码

# F/ R- Q8 G$ h" ]或者   X" s( b; q* P1 Q. F% H- Z
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

. f. ?$ u! b) U1 y! _( E+ }
" B) |: `, P5 H匹配所有 ; [6 ?+ P1 I* `' m" P$ x
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

/ x# U; i" R* v3 F* h3 R  A可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
- _* I& s% ]. K8 c/ o4 u( p! k可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } ; e# G, N6 y1 r& V* P6 _
2 [% |8 \( C) y5 g" [& |) D
查询不匹配name=B*带头的记录
  e( G- k; w, B% ^9 |0 ]1 I
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
. T; Y5 m+ {( n7 h
查询 age取模10不等于0 的数据 % a1 o9 k7 ~- y5 X: v' D+ f
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

( G! a2 `  ~6 S2 o( j; [! [$ g2 W0 e/ u
#返回部分字段
7 R( |8 R7 K+ w选择返回age和_id字段(_id字段总是会被返回) ) J% K* W3 w- j7 {' @
  1. db.users.find({}, {age:1}); $ K: D5 Z+ O* f5 u* U* v2 w$ N
  2. db.users.find({}, {age:3}); ) u; a" {. ]" h: [6 e5 c
  3. db.users.find({}, {age:true});
    6 u$ l) m- t. _- g0 J8 n: h4 c
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

( ]; A! `. ]& U- Y% L4 x' u0为false, 非0为true - m) D$ p. p* t; l3 j( n: m' p
# c- p9 w+ r/ r
选择返回age、address和_id字段
& O. E- W  m0 x
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

5 q( Y1 s+ U3 s
7 e( q; U2 {3 T; E9 N排除返回age、address和_id字段
/ i: H1 J2 x: t% ?
  1. db.users.find({}, {age:0, address:false});
    # [6 f5 Y3 |! _* @
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
6 X, U" q/ r1 c, f- s+ F; o

$ P$ a$ q$ U- W数组元素个数判断 2 B5 @7 G; X" ~! V% g1 o5 }
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
# B4 j; j! r' k$ l! _( }1 I匹配db.users.find({favorite_number: {$size: 3}});
% V! T* O" k- ]: h) `不匹配db.users.find({favorite_number: {$size: 2}}); 2 N8 u$ M1 e4 [  Q8 \& _  }4 c

0 r# ?7 N: C0 E$ O+ N% H+ M# P/ Y# q$exists判断字段是否存在
, r5 m4 z" ~. V! d; O0 ~" m7 Q5 p查询所有存在name字段的记录
6 J9 A0 {6 B" f7 r6 g; s5 X/ d
  1. db.users.find({name: {$exists: true}});
复制代码

" j. e9 }9 a! [6 U* k: j/ i: H. b查询所有不存在phone字段的记录 8 ^- M& P: ]2 Z; d
  1. db.users.find({phone: {$exists: false}});
复制代码
/ q- n* b- i7 n, }
& f, \7 B) t5 b' ]1 D
$type判断字段类型
& z/ E/ _- U2 J, ^: [, y' M1 U查询所有name字段是字符类型的 9 O; M8 z3 f# o0 e% U
  1. db.users.find({name: {$type: 2}}); 2 z! o! S, @0 C+ L
复制代码

$ E. b( f  W. T9 p查询所有age字段是整型的 ( Q# n) v: M  t8 d. ]; n6 P5 e
  1. db.users.find({age: {$type: 16}}); % y1 z" ^, o9 a4 W. w
复制代码
# P1 C. j. j) U- e
对于字符字段,可以使用正则表达式
; ?$ M2 W* l8 Q  i! w# i3 Q查询以字母b或者B带头的所有记录   H; z& ?& x9 S
  1. db.users.find({name: /^b.*/i});
    # [+ n8 q+ E5 R2 L& g+ E, n
复制代码
# {& A8 l0 T2 O7 Y( K3 C  Q
$elemMatch(1.3.1及以上版本) ) K6 O4 [) @7 {% Q- {8 o' }3 L
为数组的字段中匹配其中某个元素 9 K8 F/ w0 q7 v

* E. X+ U: u: Y' e1 }Javascript查询和$where查询
( x4 q, w! m: r$ l  y: a查询 age > 18 的记录,以下查询都一样
1 G7 h( e4 P1 _
  1. db.users.find({age: {$gt: 18}});
    + V. i* T( ~4 b; r( u0 S) v& H
  2. db.users.find({$where: "this.age > 18"});
    2 V) s% z1 X( E8 {6 M8 }3 H+ t
  3. db.users.find("this.age > 18");
    / V* D! F9 _& _3 T0 ~1 [
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

; t6 u& E( r+ N% E' S
6 {! z/ U% b, h: F排序sort()
* _* |% i3 y! q2 p. p: S以年龄升序asc
4 i# ~* K# a* M/ k0 A6 [3 n
  1. db.users.find().sort({age: 1});
    # r  t4 U" K' P
复制代码

* K. y! V8 X' s2 }" m% w3 e以年龄降序desc
9 s& P+ [! J3 W1 p' M
  1. db.users.find().sort({age: -1});
    0 J& t% G3 c$ ?7 n  S7 w
复制代码
$ f% Q0 ?7 ~# ~+ M% L: f$ H* \% b7 V% w! A
限制返回记录数量limit()
3 V" E1 r" W: C. Y5 R, L4 Y返回5条记录   d8 _  m6 N& x4 c
  1. db.users.find().limit(5); * X8 a/ s8 W7 Q+ X+ D! m
复制代码
3 j9 ^  k$ S3 {3 Y2 N6 P
返回3条记录并打印信息
+ z$ s* {1 @) ]+ h1 @# N) ~
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});   t9 H/ b) m9 z; k1 ^
复制代码

+ ~. b7 s; n) y* U  g9 A' m结果
* u% M6 x. ~" a9 l" L
  1. my age is 18
    / h3 w" A% p7 M& j
  2. my age is 19 ! |( r8 o8 z  M' m* N: g
  3. my age is 20
复制代码
# s2 Q& R; z! F+ j: R/ \
4 C2 j; P1 q$ Y( y0 x4 [
限制返回记录的开始点skip()
6 A1 {9 D% v5 U5 i  I0 z6 a从第3条记录开始,返回5条记录(limit 3, 5) 2 s3 Q( q, Q( I, X
  1. db.users.find().skip(3).limit(5); . U9 ?# k- L& J2 P0 r* m! y
复制代码
. b1 o2 N2 K+ J9 P6 N* C
查询记录条数count()
9 l8 Q1 H+ o6 F- N" Z8 Hdb.users.find().count();
5 G" I7 ?  B* e* i- e% C& tdb.users.find({age:18}).count();
' J/ W/ `. m8 @) j! w8 P4 f以下返回的不是5,而是user表中所有的记录数量
' G# i4 C4 g! w8 a0 a' |% B( P) V7 `db.users.find().skip(10).limit(5).count(); ' h4 t* I% W8 r$ V& i3 b: o4 m8 u5 J' J
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 0 F! q7 u) a# `: @
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

9 E3 n, o1 Y6 m) A: ?0 F
; e. ]" u1 {" c( d. n6 ?2 }% u分组group() ( c7 q0 R: q4 x. C
假设test表只有以下一条数据
  B- b# C4 q" e. m# n: C
  1. { domain: "www.mongodb.org"
    / H7 j4 Y4 k" ?6 u
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} ' Q% A) h4 W9 L5 t
  3. , response_time: 0.05 * T4 }( j( b9 _  A, n0 p
  4. , http_action: "GET /display/DOCS/Aggregation" ; u# I# }3 V% y4 L
  5. }
复制代码
  Q3 D9 z$ r; O. j5 ^* W( m
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 4 P& w$ e1 [0 }6 {; [' ?6 M8 b
  1. db.test.group(
    ; @' i1 j1 \& |. f* T3 G
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} ; J& o% H2 C0 n6 [
  3. , key: {http_action: true}
    # v' b0 ~% \% [6 x# w; |8 q- r
  4. , initial: {count: 0, total_time:0}
    1 q4 P& R1 u9 M2 w: B
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } . ~" a; }0 t$ W  R5 _9 ]4 d
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } % k  O# c$ L5 u
  7. } ); ( }  E5 j' |) d: v7 T+ K) m

  8. ' ?$ Y6 L& ~' B3 h+ A
  9. [ ; T; {( }" W6 G" V0 W0 ^) Z: u* ]
  10. { 9 b" o( ^9 O/ n& H
  11. "http_action" : "GET /display/DOCS/Aggregation",
    : d! U) X9 P1 T% O1 O  B
  12. "count" : 1,
    . j3 i! h4 A( Y! Z) y! [
  13. "total_time" : 0.05,
    ) _: f% c3 T$ Z/ j1 F$ M
  14. "avg_time" : 0.05 . t! v1 ^( o+ I
  15. } " }$ E7 {* a! \
  16. ]
复制代码

/ s3 g' p9 e: j4 h$ j! M! ~6 G! y" g) l

8 D: o' B& ^& C" u# S3 h9 A# T; p" }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  R% b" \% o' x- h8 l4 w
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

1 N" j& d* u8 P. c9 _3 o. A1 f+ G

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

' H/ |$ M7 A0 k" s: [. L3 A. ]2 \# h
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

8 v; ^/ v% p+ b
9 z1 y3 }! p9 d+ z! F& J& y. O
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
* a9 A6 h- ~6 I4 @
% [, O! r  M* s, E- O% C9 p4 E
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

) u) o  H) v4 M  f0 @2 t) X6 X1 ^( ]5 m6 m, W3 q, @
输出如:
  1.         
    * {9 O; u& Y2 H# V, b7 x' w. v
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

' w+ b5 f# I5 p. H) Z! N+ S- W' x) I' d

7 V8 }: H3 d7 W! K0 L- [
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"" X9 ]: D, _: K( l% g3 m8 m
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"8 X7 @& _9 `/ S0 K2 M
  3.        xmlns:context="http://www.springframework.org/schema/context"8 S7 @; x$ r6 O( u+ v( a
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"3 I! e( P* J, k, P4 \, n7 m# G. H
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans9 P2 i7 ?' D6 {
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" I9 |: G7 _* ~/ }: j% Q  k9 t
  7.           http://www.springframework.org/schema/context
    & W( _* L5 ?7 D5 z" i
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    8 d% ~+ k( e! T9 X/ p1 `, B7 e
  9.           http://www.springframework.org/schema/data/mongo
    9 f9 ~4 n+ }4 c7 _. c
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">1 C  n$ |8 {& ?* V

  11. " u# x0 X% Q' j- N: ^$ [* a  _5 K- S* O
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    , W) u3 H8 Q' P' W4 E2 o3 }

  13. 7 R& p  g1 x( I  m6 ?. j8 |/ {1 e
  14.     <!-- Default bean name is 'mongo' -->
    ; _3 Z4 `3 K4 J7 {8 k8 J3 j
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    7 h1 S! X4 q( {- J
  16. - `9 E7 @# ~* i/ |: P
  17.     <mongo:db-factory id="mongoDbFactory"
    1 K! P1 f; ^+ t0 S
  18.                   mongo-ref="mongo"6 r9 y, i1 y5 z' F
  19.                   dbname="mongotest" />
    ' x, \3 P* E# f" o+ E+ H% y* t
  20.   B" ?. Y, T1 s& I8 ^5 s
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    * ~. d: V( e: b& y: [
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ( k  t4 h; b9 G$ Q
  23.     </bean>  E" h" ^2 _- W& K- V- d
  24. </beans>
复制代码

: Z$ W$ {/ a( ^' H7 P) T
" p( N; G# x0 A# J
maxmin的测试
  1. @Test3 e$ N+ m4 Q5 Q$ ]4 c3 s
  2.     public void testMaxAndMinAge() throws Exception {
    + |4 d1 X) f% a, }5 p
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    4 y, _; `- s; R8 [/ w* _: Z; A0 F
  4.         Person result = mongoTemplate.findOne(q, Person.class);# c& g( Y" ?* D
  5.         log.info(result);* h* D6 e; R( }  k' j% Z
  6. 5 K+ R( i! Z, \8 K' C( z9 l
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);( V, c& F! ^* c+ b, u* c
  8.         result = mongoTemplate.findOne(q, Person.class);
    ' G8 r# n7 f% S7 P  E
  9.         log.info(result);  q: D9 Y2 J3 p
  10.     }
复制代码

+ ^3 B: m+ w9 ?5 M/ w, `9 G( Z$ F- L6 \, r% ]& o
distinct的测试:
  1. @Test& r5 n% U0 I3 O7 C
  2.     public void testDistinct() throws Exception {6 b9 f% j2 n6 q; \
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ! Q# B# u$ B* |$ q3 c3 B6 x
  4.         for (Object o : result) {( V' |* |8 N8 r; J
  5.             log.info(o);
    % X5 Z4 c& Z! D
  6.         }/ v3 `$ [8 q1 V) `

  7. - O2 G9 n8 u' e# }
  8.         log.info("==================================================================");! c0 S( @& A" ?' Y: |' z
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    & n* D$ b; B6 b: d& \
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());8 [2 t' l- `6 Z' O
  11.         for (Object o : result) {
    ' Z% r/ J; q9 N9 ?; _' _
  12.             log.info(o);# q, B- a; X# d( ]3 [; M
  13.         }
    1 Y9 u) d# c# h$ g- o1 S' |# Y
  14. 3 m, y$ t% ~  |7 F0 l
  15.         log.info("==================================================================");; C) ^9 F. |- U$ h# A# L! K
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");3 d+ l5 I" N/ g% q
  17.         for (Object o : result) {) j2 p' S2 ]( w& g0 t* q& W
  18.             log.info(o);
    # G" i+ |  \% N" f4 r; C
  19.         }- M2 J& O( w' W% X1 L7 P
  20.     }
复制代码
  f1 N: L+ @; s, [/ D& _, W

% n" ]2 [+ C; I  n: S
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    5 q% ~% U) F2 \% S% S
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    8 g, F( E" b9 a4 Z
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    3 J' w* k+ H1 l+ f7 _
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    - U5 |# U  B) k6 }5 d
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni3 W( q& p5 d7 @3 W
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    3 v  d! B7 O( O' }2 c" K
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    1 [8 G- ]% f3 [
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================: {- j* f% s9 l" x; S' e
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    3 q- m; t* [  b! G
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    7 I/ f, p: b& E5 L* t& z4 F
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789; p4 v' Z% k! r
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876545 [) c3 I3 V9 c1 D- k  e5 R0 g
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================3 |: q' k6 ^/ h" M
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    - V+ Z6 e' V; `9 ^9 j7 m# E
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb9 v$ y' y: p: t# J& u2 p
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc  R& l3 X# R; x
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www- B( i5 E$ e! a
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    $ B* F; V0 p  Y* X
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy4 B: h$ E( |1 L3 b. e, L0 A
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    ! F" x( w4 ]% G# ?5 t0 G# b. P
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr" ~9 x) U2 ?! ~2 T& ^7 T
  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
复制代码
7 {9 g: s5 r1 [8 Z
. x$ r& U; @. b, b3 G* `' P
这里我要特别说明一下, 当使用了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等信息。

' \/ @% L, [; t& r2 L1 f. y+ s% T0 r# M# I& Z

, x/ c0 H! m3 B( q; ~0 ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 20:00 , Processed in 0.076606 second(s), 22 queries .

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