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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
! \% X) y% P, N' h4 W( G5 y) ^  k, \; X* k  b
1 ) . 大于,小于,大于或等于,小于或等于
$ n. F% Z" @" l6 D. r0 v9 ~/ p# c+ Q1 ^0 V5 v' Z. k7 Y; w2 `. a
$gt:大于
* W; F. z$ N2 z  i- n3 Z5 `- ^8 s$lt:小于, S6 h8 M' l8 `+ t9 N
$gte:大于或等于
9 w7 x6 Q" z# N' s# w  s" z$lte:小于或等于# p% O$ h* D2 |+ ~- W
) o0 P7 s2 d- n& A- g5 T8 E9 u
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value) ^$ d  ]: H: L9 o
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
      [6 K' X# \! \3 S* A( i
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value+ x- N$ b4 Q2 Q
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

+ \5 @" z' ~1 i. ?# C" w3 g& x
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    , M) q" N4 S! Y4 C" `( {% |
  2. db.things.find({j : {$gte: 4}});
复制代码
) D. f' x, ~6 }! E( N
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
5 O* X- A4 j  L$ [
- L1 v$ m/ A/ l9 A, a8 A

0 h. {0 I% L) }+ i, V; w0 |4 Q
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

" E% G2 a  V5 Q6 f; ]; e4 [
3) in 和 not in ($in $nin)8 \) ^% j' h  ?' A" A( c

: N7 Y8 u6 E; r* D. A( r语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

2 n9 U$ Z9 M: `2 w
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    ( C9 ]* w3 q# m8 J, y1 y
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
; [: f! c8 ^. c4 h% k* _( e& f, T

. O& N) a  {( H4) 取模运算$mod
9 L0 W6 C* T7 G( n+ I
- j2 G: }8 M1 _) b2 P7 U& |8 f如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
) Q5 f. x" d2 Y" Z$ c
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

! S' T$ k! }1 s9 u2 ~% D4 S

' \2 M9 {& C) K$ r5)  $all
4 m; j- E4 A0 G) B8 h
: v5 C; D8 X' Z) u; w1 L7 b$all和$in类似,但是他需要匹配条件内所有的值:
2 @0 p0 }. r1 t$ j8 X
/ R' S" j  V$ Q7 t; S, t3 X' _如有一个对象:
0 T9 c, z* J" f
  1. { a: [ 1, 2, 3 ] }
复制代码

8 m( P1 [- C: S1 s
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
, i* }- N: l8 Q) z- K' H8 _
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

: k6 Z* }6 U$ u% |
6 O2 A/ w5 V& b. k" K$ w3 u% k; u4 v
6)  $size* V" ^, [& ?* S* i: c
" p5 B9 R# x* i! ?% F6 W- I0 `0 V% \
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
& D: _, C$ c9 ]: c: @) l* R& P- Q. x# e( A' m
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
5 N: c7 A- Z% y5 @& Z  r) 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.

0 c+ I* s& z! u; v$ x
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    : c, a9 H" k3 Z* {- T1 V
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
, O8 l8 N# N5 y7 }2 l( U
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    4 H, A4 V: Y8 A3 Z( {! O5 V
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

& H5 R& `/ m6 `8 R' E1 G* t$ k
9)正则表达式
  v, E6 L  J0 n+ W3 Y. V7 D2 M6 k. E, y
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

) v. b/ E5 ?# B7 p4 |1 h
10)  查询数据内的值+ f  ~) J% V) E: T0 f8 t& U0 W
( b9 E3 w; R6 j- _+ ~* g8 `
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
. u. }. d8 A0 }& U6 {
11) $elemMatch7 o7 Q0 @& h& n

: q- z5 o' e7 o如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    2 V- t% L7 o/ y  e/ o( G8 T  r
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  * }& D( c! E$ t* I# U
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    ) p3 l# L: Y2 H. W& I6 s2 K
  4. }
复制代码

8 t! L" u+ t8 O. U( w8 u/ T$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )) s8 [+ q8 i; n* L" _
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
8 w% w- D2 x5 J( m: x; O
# C9 P8 r' j$ G12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

5 m1 t% ?" {3 ^% U+ ?, @9 Z7 A
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

6 _' e/ P5 j$ }( o+ m( ]
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

7 v7 b+ z6 o+ C3 x& d. @2 B* d) Y
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

2 I9 w/ O1 J5 S% Y+ C
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
- t0 e; H+ u& s: o' d& G
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

  c. ?" l  S/ p) i- t. x
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    : e0 h" y+ s. C5 B* Q- ^
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

2 g, y, ~5 j4 p( V
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
' Y; P1 M" C0 o, e: u! x! }. l3 O) Q0 ^
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
& ]5 p2 h9 l, q  }5 l; q. r! I8 ]# {2 d- s% r6 |
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
5 g# \, I6 u% M1 |, c2 z
: B" t( z5 l4 w8 z8 X+ N版本二:
2 [# l% b2 Z% v+ o9 U, l) r
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

& W3 b, B! B8 s/ S" _
  1. use admin
复制代码
+ K( Z  E$ c' k& P
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

5 n) C$ c0 T; ]* ^6 o
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

5 w+ ~! G" o0 ~8 N
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

4 w# a3 O. E) k2 D) P; }  U
         5. #删除用户
  1.           db.removeUser('name')
复制代码

/ R$ Y" Z7 q. p1 t
         6. #查看所有用户
  1.           show users
复制代码

8 r" K6 B+ C' s( H7 @: ?
         7. #查看所有数据库
  1.           show dbs
复制代码
( ]$ H* [+ |/ ^$ n5 A( S/ M
         8. #查看所有的collection
  1.           show collections
复制代码
4 G: t; C2 K6 i7 K# O
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

6 z3 t4 C7 ^6 Z8 y, |
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

" |! r  l, W% Q. Q
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
% n# a1 }. l. [) \7 ^9 g
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
6 [2 T2 W4 Z0 d3 J: T$ {' B
        13. #查看profiling
  1.           show profile
复制代码

6 T2 E7 W: H/ C! z4 @7 x. T. O3 {+ \
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

. O; g, V: Z9 x' M
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

. Q( ~& e5 ^& X; E) q, g* I+ |& {
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

$ ~" P% y. h# ^# ?" V: \$ R* |6 ~: [  Y
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

4 |- y# p& X' T7 `
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

. y+ w. }- |, l1 m5 i; h# B5 \7 w
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
% ~, r, B$ g. n
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

2 y) h5 v! C) ]3 H( g$ T/ ?
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

% v7 O5 \3 x8 A- B" W1 _! w" w
   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+ \! R/ o9 k5 o( Q
6.  高级查询
条件操作符 % W: z6 x; D" X0 @
  1. $gt : >
    4 T) C4 S2 J1 ?
  2. $lt : < 1 G# B% P  n2 }6 Q+ M5 c
  3. $gte: >=
    : ?, w+ L8 B0 Z6 `# T  E
  4. $lte: <= 6 }* N3 e; K5 [- Z
  5. $ne : !=、<>
    * v4 g& m9 U9 N6 A
  6. $in : in
    * R' J  m6 F- I) m, m- E
  7. $nin: not in
    - }. L% s/ S! {, J' f" g  y, ^
  8. $all: all # O5 s- K2 I4 T. x* \6 J
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
- x7 l" y) d7 ^3 S0 v& q" K- |

: _  L+ W( R/ f0 `$ i  b8 r查询 name <> "bruce" and age >= 18 的数据
6 X# T3 j( R7 l- F
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
. I7 g+ Y3 r, H9 x5 @

) I* U2 ^" ], M0 P查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
8 T9 [% d6 a# A" Z! C* S8 Q  c6 Z% K
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
, q! A; p7 P# h" f: B( r

' [# R8 y% \9 ^( H, @  I查询 age in (20,22,24,26) 的数据
% [, I2 e3 C$ _( J4 G: F9 n
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
0 O- ~: ~& S" E/ a) `

  b! b7 O! {$ W  D% Z查询 age取模10等于0 的数据 : |5 F1 W; [9 _, P; R+ v( c/ x3 W- k
  1. db.users.find('this.age % 10 == 0');
复制代码

& \: w. u, B/ t1 X4 J, f+ @" L或者
4 Q& j( K  H, B6 D" V
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

/ \7 i5 }$ H/ K0 B6 ?4 A* T- }- {4 M1 `) `  ]2 v8 s* `
匹配所有   m& W1 z3 h8 Z* E7 @2 U. I7 `
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
9 g  V" n2 F7 a* L+ Q
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
7 ^9 ^5 e2 Y2 H7 r) A. A' Q可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 5 c) R! @# T. f

. e$ ]3 {3 b! P/ ]- Z0 p8 k2 E查询不匹配name=B*带头的记录
# t5 P6 U  a' x' Q" l) Q0 V2 ]
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

7 F3 C# h& A2 B; I9 E1 B查询 age取模10不等于0 的数据
. z7 z, D7 l! T2 ^6 d4 y: ?8 Z
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
# y* q+ ~8 H8 ]0 A3 J! I* j

% O+ ?" L% |" v8 Y#返回部分字段 " c% B# R& N. j! C* d2 S
选择返回age和_id字段(_id字段总是会被返回) ; l8 v% G6 f* t) D( f$ c% R; J% a
  1. db.users.find({}, {age:1}); / }) Z( m* U$ u
  2. db.users.find({}, {age:3});
    : I0 Q$ O& ^' E3 o3 t8 n
  3. db.users.find({}, {age:true});
    3 X/ @7 g( m0 p0 p3 v5 C. e+ d
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
, v1 c+ r. b2 G7 v
0为false, 非0为true 4 P& y  Y4 K8 k3 \) K. K

3 [6 V+ k, M2 j! D  w- k1 n" `2 Y选择返回age、address和_id字段 6 O9 P7 {% P; E% j# L/ S
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

4 |8 {$ D$ c- v% [
( O3 b. L& ~  K* g排除返回age、address和_id字段
8 R5 b& e) F- k7 ?
  1. db.users.find({}, {age:0, address:false});
    , P) j. D; q3 _* R1 |
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

# ]& q) `1 _1 w  o) p6 A' r
. C5 A  l, L( ^: Q4 a% K# ~数组元素个数判断
. |' a: U" [1 ^3 K5 _对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
; ~5 x3 Z) U2 W; E- n匹配db.users.find({favorite_number: {$size: 3}}); ; ^& r: m( W, d4 z/ m
不匹配db.users.find({favorite_number: {$size: 2}});
7 p0 m) F1 [6 `/ y4 s+ C' O9 _6 [# Q* r2 p1 b
$exists判断字段是否存在
0 W; ~7 [6 ^+ {7 a! D' d查询所有存在name字段的记录
3 q+ x" s. ~$ t# d9 c7 M5 v; j
  1. db.users.find({name: {$exists: true}});
复制代码

  d; B' n- h9 R查询所有不存在phone字段的记录
! K) a8 N! K7 P% e# _8 G) u4 p
  1. db.users.find({phone: {$exists: false}});
复制代码

! d5 l" o) e5 |% l4 y/ l
  @8 k% M3 K9 ?# L/ F  O$type判断字段类型
& Y1 P0 b/ w/ q# g7 h4 ~) r3 o查询所有name字段是字符类型的
* S2 X: ~) ?3 g% s
  1. db.users.find({name: {$type: 2}});
    * a2 G( l# l: a5 }* X3 b8 A
复制代码
' ~) Y0 w7 b$ ]7 b
查询所有age字段是整型的 5 [0 j) q+ N8 _' G* @
  1. db.users.find({age: {$type: 16}}); , l+ g8 P9 Z1 b4 K3 n
复制代码

5 q0 F' r1 z6 T. y9 J0 z% z对于字符字段,可以使用正则表达式
! M" [. y0 k; b, J查询以字母b或者B带头的所有记录
9 h& w* V; |* `
  1. db.users.find({name: /^b.*/i});
    # e! \; O8 w) C0 _- e- `
复制代码
  Z" ~) p5 Y8 g& S
$elemMatch(1.3.1及以上版本) " `) u3 V* c; n: H1 Y
为数组的字段中匹配其中某个元素 " @  l$ S3 V' ~' j+ X' ]

$ i: u  C6 I" q- p. [7 T( C! WJavascript查询和$where查询 , I7 M9 P* e4 z3 R8 T- j- D
查询 age > 18 的记录,以下查询都一样 & B  m3 m) _7 p  h& ~( V* c
  1. db.users.find({age: {$gt: 18}}); . L# {' M" G& n1 ~
  2. db.users.find({$where: "this.age > 18"});
    6 |0 a6 C8 N* m
  3. db.users.find("this.age > 18"); + {4 S: c% p, s7 M' t% Q
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

% o" e% p$ w% {- E3 i- ~) Z; I
) {# \, u) f3 r, o; g排序sort()
0 z6 k7 J( {4 e5 i5 ?以年龄升序asc
/ U" s1 L3 E& t4 l0 ^( c
  1. db.users.find().sort({age: 1});
    ( {; f% j% l9 W; L/ N$ R; V7 O
复制代码

- z' E/ T7 r- C+ J以年龄降序desc " d! e2 Q3 I# r
  1. db.users.find().sort({age: -1}); 1 a8 m3 d2 O0 \% w( \7 y# Y* X
复制代码
6 Y2 n! K9 m/ m. t1 N5 L' f
限制返回记录数量limit() 2 e. \* v3 f6 s; e1 C- G0 A1 b
返回5条记录 " S6 @$ m! R  `, c
  1. db.users.find().limit(5); + `8 A7 [) }$ y. J6 e0 |
复制代码
4 _% D6 P$ \' B. ]) K( s
返回3条记录并打印信息 2 X/ |, y0 e% T6 G: @
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); ) U9 G2 o( E( w+ r* K$ C: K
复制代码

" z- |# h. ]- u, B' C0 J. P结果 3 H, w( j$ j6 W# ~; E+ ^. U, t/ Z
  1. my age is 18 . {2 N: z; ~; {7 g4 X% Q* o% y' Y
  2. my age is 19 : F8 y+ i0 ?, A7 H
  3. my age is 20
复制代码
; f3 p$ `# H( D. T0 c

9 k6 w" A* i  c; S, d+ m限制返回记录的开始点skip() , H6 ~* y0 F: W0 u
从第3条记录开始,返回5条记录(limit 3, 5)
2 K0 O$ ^5 p. x" h/ a
  1. db.users.find().skip(3).limit(5);   n, R5 M$ L! K  h4 }4 s
复制代码

+ o& e7 L) y( M8 M查询记录条数count() & Z" C1 d  e* \- H/ y( d9 u
db.users.find().count(); , ~& P& f1 B" C5 i4 Y# |$ v; O3 w
db.users.find({age:18}).count(); 6 R3 q; Y* X5 @' Z
以下返回的不是5,而是user表中所有的记录数量 2 w  D3 n" M5 g6 L3 I% v; L. J0 n
db.users.find().skip(10).limit(5).count(); $ o, e) }1 S2 [1 e+ D4 T* u1 B
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 9 q2 i) v2 i1 E" ?
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
9 ^' l  T3 E# S

. h" G' M, {/ Z. j分组group() / ]0 b2 x7 ^2 X% `" S1 ^
假设test表只有以下一条数据
8 o+ ?6 Q$ {2 P; x2 e3 O) C
  1. { domain: "www.mongodb.org" 7 J3 {$ n3 t* c% P& \: O* E; f
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} 3 f+ `7 A9 Q% J. I! X* d' _7 N
  3. , response_time: 0.05 * o' z1 x5 Z% y( Y0 u0 _4 Z
  4. , http_action: "GET /display/DOCS/Aggregation" 2 o: ^( ?$ B0 I4 R% i2 F
  5. }
复制代码
( f7 y6 @2 H* Q
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; , a/ B$ q4 R; Y0 d
  1. db.test.group(
    - C8 d: c' z5 V+ E! Z/ M! y
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    % q- u& l* L+ x9 |  y# O( I; R
  3. , key: {http_action: true}
    3 c* f# U2 @! v
  4. , initial: {count: 0, total_time:0}
    / [. P) d* P; m: F# v! y
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    3 L, A" Y) K2 t, u- M
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    / u* c; c/ ?* S  q+ `
  7. } );
    . Z: }7 `: k0 T4 a' F) h2 e
  8. 7 C2 S3 d! ^& _
  9. [ # J! U+ {4 }1 ]: L, c: E
  10. { ! G6 a+ v: |; P6 t4 }& V$ ~" g
  11. "http_action" : "GET /display/DOCS/Aggregation",
    7 h( w$ C9 _# s* S+ k8 X
  12. "count" : 1,
    ' t% s# x8 x# V" O$ j
  13. "total_time" : 0.05,
    + T/ i6 w) N9 M* F5 W. \
  14. "avg_time" : 0.05 , H. q7 X* _5 d& s( E6 v1 O0 V# i
  15. }
    2 a4 p* X, m9 l& |+ r+ v0 w5 ~
  16. ]
复制代码

! V. {8 L6 X0 ]0 ~  q8 Z; Q4 p( E( N* Y8 a* k
: l0 O! Q+ K& o
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 和Min7 g& D( h2 S5 S3 Q
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
# U. n, v2 J5 U, z8 m  \* ^
2 A  H- d+ x. c! i

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

$ i' ]$ i& Y1 e& X! n7 d) }: `8 U0 ?" l, F! r6 y
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

  r) J+ ^7 W5 C$ U+ U
7 y+ }% m* x" ]  g2 H+ [4 S5 l
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
/ n9 E7 L) b  p  C, E- S
: w7 Y4 j2 u' i5 f, B
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

, a5 x  B$ s& R1 L. H3 C
+ s9 m* \1 k3 e. |/ o
输出如:
  1.         ( k7 X7 n0 d4 W2 |1 ^% _; L/ l
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
$ \9 M8 r% O0 Q% K8 y

8 J5 ]6 ~& S+ g4 m  K( H( D! q9 X4 i# F
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"1 H# w+ M& q! t, y$ E9 J  m
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"5 K: [0 d# x, K. ~3 _' ?, F. A
  3.        xmlns:context="http://www.springframework.org/schema/context"9 y- C% p0 G- B$ h; P- H
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"0 B0 n5 b: d, K1 j1 x
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    * x- H( S8 ~7 C
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd3 }6 R& f1 ~  I  [
  7.           http://www.springframework.org/schema/context! n% t8 ], W! b9 h8 e; }! p
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    : {+ [9 k: `  g2 M7 K1 e
  9.           http://www.springframework.org/schema/data/mongo
    ( l# T/ _# {4 b  t- [
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    * j. H: c1 g5 Q

  11. ) O5 [6 I4 A' m9 N6 d2 k% V
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    / J. ^2 r, ]8 x: c9 u

  13. : J( |# _( O4 L& V- T
  14.     <!-- Default bean name is 'mongo' -->6 L0 I4 E7 r3 o. P* d1 ?  |6 r) Z
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    - G* V0 E! u* j

  16. - o/ N: K1 N- I7 S
  17.     <mongo:db-factory id="mongoDbFactory"
    ; G+ P  K* y+ S( Q" i' T! z. {
  18.                   mongo-ref="mongo"
    5 L9 n2 d/ h* ]% Y% T  k
  19.                   dbname="mongotest" />
    * l  D. |- o- ]. i6 ^: [

  20.   |7 F; L4 u3 T7 J0 r- E
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">0 l) r' U$ O$ i6 K% l
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    * \2 o; s, C% B! M. y; ?* \
  23.     </bean>% N7 e2 y; D$ T
  24. </beans>
复制代码

6 J) }7 S; e0 s2 T+ P

, x9 d9 J1 ?' w& Y
maxmin的测试
  1. @Test
    8 o( E" ?8 f8 E+ _6 |3 F
  2.     public void testMaxAndMinAge() throws Exception {
    5 t2 Y3 ^8 H) h# o9 A8 H
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);9 P; B) X4 ]( r: u1 T7 I
  4.         Person result = mongoTemplate.findOne(q, Person.class);; m0 J0 _# }' W! {8 N# s
  5.         log.info(result);) G& Q( k/ S6 n. c
  6. $ s& s/ ~3 s" T; X' x
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ; z  M" S) B3 n
  8.         result = mongoTemplate.findOne(q, Person.class);( P2 j3 n6 w8 A  y
  9.         log.info(result);! U( r5 Q" M! @4 d3 ^
  10.     }
复制代码
5 W6 P+ Q6 Z& }

; s, a4 y. P* J/ f
distinct的测试:
  1. @Test& z0 p/ u+ u/ S6 z. Z4 c- Q
  2.     public void testDistinct() throws Exception {
    9 \! H+ l7 R+ T3 \
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");1 z1 J+ v9 Q5 X/ L- p7 x* x) s! Q
  4.         for (Object o : result) {
    - ~3 F# V; @; y) B3 L4 a. K
  5.             log.info(o);
    3 L) H" r) a; j
  6.         }
    ; j3 _. X6 \2 E% z: a4 E0 w. Q
  7. 4 g& ?- O4 g( U2 c/ w) X! A6 C; c
  8.         log.info("==================================================================");* R) {$ n) G" X; q/ j; F9 b: z
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));& D- A8 S& z$ Q7 y1 v
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());* E6 x; y# N& w0 k' T; z
  11.         for (Object o : result) {9 h1 j3 p( j1 o& \; S9 A
  12.             log.info(o);1 G4 x& T  F( ?2 ~
  13.         }
    & G. M/ @$ d) g1 b& B  q0 q

  14. 4 v: i5 f! ?* Q  x9 l
  15.         log.info("==================================================================");: ~. h" Y- @9 j3 b* F" I$ u* j% C6 U
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");$ Z$ T2 B% j) C  K( b
  17.         for (Object o : result) {
    6 ~& Z" P; \, g. F/ j$ A
  18.             log.info(o);
    " ~* n, |- P3 c! Q* G1 J! u
  19.         }
    & |5 Q. A4 E0 W$ }" K
  20.     }
复制代码
: U6 t' V3 c/ \/ Y7 W  a
5 E' l' t8 A8 Z' X! a
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    % g/ I9 q7 C0 G0 Z7 @/ M: t
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 3456784 ?5 g3 x! F1 {- a
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789: x# C& G! j8 s: _
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876543 p& A* T& v. F) R/ X/ P: b
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni0 |/ `3 U: b) \# z+ ^7 Q
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo+ X$ H% N# E) l4 `8 c) G* p+ g
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456  G/ ~" |+ T" n8 x
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================& M1 r+ l$ w- |  z3 ]. j+ X
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567, U: R7 B% |5 w9 n1 z
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    * d7 a) O/ X4 r4 |$ m# `: ]
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    ( {6 l/ y3 _" C# n+ E) B
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    ( F  {" M* ~! ~5 X8 M9 `7 n& b
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    3 X, k! W0 j* j5 w
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    - t1 \! Z- ^8 [; H6 S
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    - p1 C  Z, Y! }* J( m; I
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc4 T  ?0 w8 U7 i
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    ' x5 v  }- N  o7 G: ~5 ~
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx. j& T( P% a8 s
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy- T5 x; Z& G6 y) M6 B# v* `
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz# U: k' G, }% W3 d& @+ y2 N
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    ) M4 a; j9 Y: L8 i& Z1 W0 P" S* D, i
  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
复制代码

6 c) f  M+ l7 y. B9 g1 |* h
* }( _0 G0 k4 i; X2 u5 ]$ ^
这里我要特别说明一下, 当使用了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等信息。
- m1 c' \: W4 l5 E, Q

0 p) p- J1 R6 h# E& @% o0 \; j3 ]# N! H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:39 , Processed in 0.082014 second(s), 22 queries .

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