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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
版本一:- A% x; z! U  E* U

6 c3 L2 Q1 }& e4 U/ N1 ) . 大于,小于,大于或等于,小于或等于3 `4 d0 U9 l) x9 g3 U4 O7 B
$ T) R+ X! a8 F# [
$gt:大于
! z7 Z! O5 E- d* a- \5 t, `0 m$lt:小于
) P, P/ s) D& d6 [$gte:大于或等于
3 m6 z/ N1 {9 Q- L$lte:小于或等于9 ]( \6 O6 h' M

$ A) \5 b8 _" Q& W' O; n* [' K' U例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value* b3 Z  N5 n7 e% E( Z  ]# w
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    * c- }1 ^' T/ {0 x
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    8 w' X0 [1 C4 ], `  m
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
2 ^; `& Q- b  \" j1 p1 a" `' U
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});4 H7 Q5 ?" s3 Q% L1 |
  2. db.things.find({j : {$gte: 4}});
复制代码

, Q& e% W) I2 J' L
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
) k. G+ S. g  @! E( L. j

# H+ C/ T8 D' `# g+ f4 u% g! v6 }& P3 `1 c. L) t& O7 ^
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

/ s- G6 z% w, O
3) in 和 not in ($in $nin)
% Z0 b& O  e5 ]& W# E( m6 L: m" g
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

( ?- K1 X' z- j* U
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    5 D) q7 @7 |+ ?# R) q. B, c
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

# b% l; {' E: C& E8 O- m

- M2 U. h& S; x" Q8 D& [2 H4) 取模运算$mod
1 c' }  M: u" j, ^' ~6 }8 F& @6 Q, q; X  b  Z1 k* M0 C1 w
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
$ h, s3 O( Q" [3 i: x
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
- K6 ~) x, u, N( D, A) ?: C
: F; B/ u. M. ]% a. r0 T: X1 C
5)  $all
. G$ @* K5 B  @% f  g0 f/ C( f& [5 f7 N) J
$all和$in类似,但是他需要匹配条件内所有的值:# i( I0 _8 @1 W3 n6 j; b

. n4 j! [6 P9 K' v如有一个对象:
* E9 J' {# C5 q) F) Q  A/ g
  1. { a: [ 1, 2, 3 ] }
复制代码
2 W4 U# w8 p. S, T
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
' x, K& ]" q( f. y
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
* w/ F! E9 d" {2 X8 Q
; Z  w& j4 C& r9 F
6)  $size8 k- k6 u- e6 A, x
, O  |- Q; b! x8 Q+ J
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
; R3 J% z; M! M) [: k; @/ ^7 g
# P* E. H5 ^) @5 C  w下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
9 p) W/ W$ K- Y& Y
官网上说不能用来匹配一个范围内的元素,如果想找$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.
$ V% Y% ]+ N8 M+ F3 H5 G& k
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    ) I/ D3 u8 g. j4 H5 i! h7 B& t
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

4 o  Q; U4 O2 r/ G+ N& s
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string9 X& N+ Z+ Y9 C3 R
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
) Z5 \/ k  f4 Y5 L: [
9)正则表达式  M6 K; K$ b; t/ ~

' y) T- ]( s: H4 ^mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

3 q- d" \" {2 O* H/ n- F% `7 c
10)  查询数据内的值
! t0 x  S5 O* ]8 c, i
0 l; F- d/ [+ s6 t$ V# T% k, c下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

8 r# s4 G& J0 R9 r3 P
11) $elemMatch6 W3 Q; q8 h# o9 T' [0 ?' r/ I% c) r

% _, v5 I* N* e$ }, E! F6 k. e如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 2 X4 G& s, C7 P, M3 p4 D* O! E
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  5 w9 K, M1 K5 L. X0 b+ a9 h
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]0 ]1 [% A& F, x
  4. }
复制代码

1 j$ n0 _$ V! _, P$ V% w$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )7 u1 ^) m$ ~; a0 h
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } ( R4 u) ]3 o) }2 q( D0 _5 D/ Q3 h
" b9 d' J' D) ]
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
/ e2 Y. ^1 e9 E  D* q
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
' \6 C: V  n# }1 O
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
9 j% Q3 Z/ x7 S; E/ }
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
1 e3 i9 }& D9 u# e6 J; b' v
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

* l) D) ], B5 C
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

5 x, @$ Z+ n4 T) o
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    ( b, ~3 t# I+ Q: F
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
1 V; N$ d) N: V1 T' y8 s2 ?
mongodb还有很多函数可以用,如排序,统计等,请参考原文。& t, l; W7 q0 G) b
/ ]8 M# \% M/ _# r
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
- R* k* ^$ P% }" ?, b, U% d7 J
9 x' ]5 T/ T/ n: Phttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions6 ]3 j6 F  ^' J) E, j

. D: c" E5 B( I0 x4 r  R版本二:. F% r3 I$ F% E( r  |, `/ V
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
# f2 R- }8 h. u- d1 ~% g
  1. use admin
复制代码
( X! }) \+ m4 }8 I
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
# X& B( v3 i& i, B
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
: w# r. a3 X& Q3 z. ^3 Z
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
4 |8 i) b. z' [6 m8 c
         5. #删除用户
  1.           db.removeUser('name')
复制代码

9 D! C9 W; ]' U3 i- \, P9 u
         6. #查看所有用户
  1.           show users
复制代码
' P) z4 f/ c9 }$ N  W7 u" W
         7. #查看所有数据库
  1.           show dbs
复制代码
) }8 |! V6 r6 q5 M* I* q
         8. #查看所有的collection
  1.           show collections
复制代码
8 v$ }/ ~* l% u) u& W+ |" @' o
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
+ l6 _( N5 _' B* N
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

4 _; a9 Z& I3 v5 S
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
* K! o3 ^6 X  K5 z- }+ u+ i
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
+ I' e$ `' d3 o2 X# _# j+ A! R
        13. #查看profiling
  1.           show profile
复制代码
1 U* D% c& o( ^* N5 f' ?
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

# v: z- T0 R3 {2 }% L5 u9 x
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

: w, ]! W1 F) X; d8 O* M  u
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

3 b2 E  t" U. G. @  ^. q0 o$ G
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

( b: ~6 ^' s7 N
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
" N" O, [! Z0 c! |1 b
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

7 t: \# V) c* Q" s9 g
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
: a* X4 ?4 T# a  |
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
  @/ B# i3 E& _; G4 [% B! R! K- d8 n
   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()
! Y$ g0 v; L+ D& P1 Z* ~* X
6.  高级查询
条件操作符 ; D  h" Z6 {$ K* ?0 |. t
  1. $gt : > 5 Z7 v2 f7 j4 U- T+ q. T. x7 U) ~
  2. $lt : <
    1 C" M' W( a+ W) w2 @1 U
  3. $gte: >=
    ! A  N- ^. |* A2 u) o  V$ i3 ^* l
  4. $lte: <=
      H, P, Z" ?  O' [
  5. $ne : !=、<> 3 {  Q' `" @! e1 X# C
  6. $in : in
    : U  ^9 a  p. Y3 Y$ {
  7. $nin: not in 4 @8 E; E( y$ |- w3 E$ f( y/ ^
  8. $all: all 5 _/ h% [; F% c7 i6 H
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

& C* e( l" }) D( J1 B! p) B/ a
' L9 y( I; f$ Z* f: C3 f查询 name <> "bruce" and age >= 18 的数据
* Y6 \+ ~6 C0 G% u
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

5 z9 J& ?6 F+ b! ^& N0 W
1 \, `0 M4 `# o2 C查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 # F" o$ k1 F8 q! V, u; F
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
% C$ y( w0 D: w6 X# V
# t9 S  g, m, O% Z: D
查询 age in (20,22,24,26) 的数据 ( p7 v1 M, b5 l/ m2 Z) v- E' R
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

* \/ ?9 b: j" A9 R
9 z7 O, F) h0 b查询 age取模10等于0 的数据
( Y, h% f! L4 N& N. `- s0 f
  1. db.users.find('this.age % 10 == 0');
复制代码
9 V8 m: l  W/ l( k& k
或者
( x- U# u- Z' X
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
; B1 y  A! R) q: Z9 F
( D3 u  `- z1 r' O
匹配所有
/ b7 M' x0 b! B0 k
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
) x% F, E, M! j! t1 V; U, H) G
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } ( E* B1 O$ i# c8 J
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 4 e" v, U! N/ F. r6 C0 t& k
/ h# d* V3 S6 Y+ V# Y6 y# D  Z
查询不匹配name=B*带头的记录 $ m+ s" j" v' A3 {: l
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

  {; k) t- s+ [9 X5 v  Q+ o查询 age取模10不等于0 的数据 ; y. _- H4 d# b' e
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

; s* X& K5 b% ]) S: b+ w, N
/ |# F9 a6 s: t: v" H6 o5 B#返回部分字段
) V) X. h* x5 V8 v) R% D) ]. n1 p% Q& I选择返回age和_id字段(_id字段总是会被返回) : h" [, a  m) e) q+ u
  1. db.users.find({}, {age:1});
    7 A2 @+ ]( x4 T- A0 Q2 |
  2. db.users.find({}, {age:3});
    - {; G* g6 g+ O
  3. db.users.find({}, {age:true}); " c, Y* ?$ s$ R
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
, Q( b5 W2 c  W& F% I
0为false, 非0为true
, f- L; @" e" B2 n: W  M9 k- P9 k: z& m6 [* l7 a
选择返回age、address和_id字段
9 M% ~/ U( H0 ^7 E7 G
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

  p5 c3 F+ O2 h2 C% Q. k9 R" J# E+ Q$ v& k! k5 ]1 W# [
排除返回age、address和_id字段
2 t+ n& f  i! u- c6 W
  1. db.users.find({}, {age:0, address:false});
    5 v8 q. b4 o5 x  B2 U, \. g
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
* Y( Z5 e  V) @
# t; A- \4 f3 n; w
数组元素个数判断
: l3 p! N" ~+ \" b( I( N对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
2 [$ I% R, Q* }6 e, t匹配db.users.find({favorite_number: {$size: 3}}); : D, A9 W; M9 Z  v, D
不匹配db.users.find({favorite_number: {$size: 2}}); 3 P/ i* k- X. b, m
' b( u( S$ E, R6 N" f
$exists判断字段是否存在   M. |4 v) r3 C1 ?( D$ [! L' D
查询所有存在name字段的记录 - }" E- ]- L/ `" x4 T6 S
  1. db.users.find({name: {$exists: true}});
复制代码
9 i* x$ N% U, d8 U4 b6 D4 \
查询所有不存在phone字段的记录 * s4 _2 b/ n0 p  @! W/ E8 ~
  1. db.users.find({phone: {$exists: false}});
复制代码

4 i3 h, b3 W2 }5 }! K6 p% R, f5 }; h% t  a) b
$type判断字段类型
# F- R0 B, [  Q9 R* g4 V查询所有name字段是字符类型的
- }, i4 l% P; g5 N
  1. db.users.find({name: {$type: 2}}); : P9 L8 G: A8 I% Q, S
复制代码

' J. ]7 i% i, {  ^: W' ^4 S# v, ^查询所有age字段是整型的
2 k/ q/ Z3 v3 |0 a2 |
  1. db.users.find({age: {$type: 16}});
    ( m0 O# G% \- A% ?9 d8 k% Q
复制代码
8 o: F- B0 m, C) f1 c1 f7 x0 {8 Y
对于字符字段,可以使用正则表达式 1 I$ P0 k; Y  P3 N- c! K: M, b' R
查询以字母b或者B带头的所有记录
; _9 p, a3 t$ O( R4 U2 D
  1. db.users.find({name: /^b.*/i}); & f3 r8 M. Y; @: l5 K- h( H
复制代码

4 [& A  ], H  d8 R$elemMatch(1.3.1及以上版本)
4 b" q+ c% s3 j9 H+ ~  j为数组的字段中匹配其中某个元素
3 ^" p/ a* S' l( b9 s8 L  V6 D# K! a1 t& Q1 {( i# p
Javascript查询和$where查询 ! M, n9 X, x* g; \  X
查询 age > 18 的记录,以下查询都一样
- _0 P4 F8 E; o( P' b
  1. db.users.find({age: {$gt: 18}});
    6 V/ M- S7 J6 ~
  2. db.users.find({$where: "this.age > 18"}); ) m8 e* h9 r$ @! A
  3. db.users.find("this.age > 18");
    # X" d% o, b: ^
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

  _2 Q* c# W' l  A1 f/ I
4 b) C6 E, b  i  k$ |. i排序sort()
; \8 T% H& {& r  \& I" ?以年龄升序asc 1 U. ]; T* j( l) \9 s5 q" q) n# P
  1. db.users.find().sort({age: 1});
    / R- f4 p) M3 N: X$ n
复制代码
* x- X; L. t: i% c- W
以年龄降序desc
7 K0 r+ L& B& F7 q/ m  y
  1. db.users.find().sort({age: -1}); 5 J7 H& u: {& L- e1 z+ [0 o4 f3 _
复制代码

5 y! c" ]0 [. k& v( G' j, p限制返回记录数量limit()
6 k# j. ?9 c1 [! K" k2 b- {返回5条记录
: Y: w. `+ x1 n7 |" m" S  Y
  1. db.users.find().limit(5);
    ; b& l6 ]0 j2 ^
复制代码
" n; ]0 f" C0 |  Y; i
返回3条记录并打印信息 # m, j8 t3 t# L9 g
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 5 a4 F& U# l2 V3 u% R
复制代码
# b5 ]3 L. Z$ r. M4 T
结果
2 T" k: Q! k# a( S: c9 J# @
  1. my age is 18 5 D7 ~' Z0 A! X' t# \
  2. my age is 19 0 Q9 }( G, q. d: ^' l$ Z) }
  3. my age is 20
复制代码

+ {) f) Q' L6 X( z8 K# P& G7 ~$ T( L8 H* T. i0 H
限制返回记录的开始点skip() ( r. }- {, `1 z' U
从第3条记录开始,返回5条记录(limit 3, 5) - j7 i: B" o- ^# I  @4 s
  1. db.users.find().skip(3).limit(5); & `+ j% f) F# u$ X' G$ f
复制代码
' `9 [4 R& D9 b% d5 ^) f* z
查询记录条数count()
/ ?3 H9 r/ Q& \! _6 o* Tdb.users.find().count(); " r/ L  B3 w8 M/ O7 v
db.users.find({age:18}).count();
1 v; o& W& m3 [2 ~+ p5 n/ j* A以下返回的不是5,而是user表中所有的记录数量 1 g+ R! j7 z# j, [  T9 y
db.users.find().skip(10).limit(5).count(); # G$ Y+ K% X% f
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 5 ^' ?/ X0 D+ T1 z5 Y7 p2 o5 `2 u
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

6 L$ Y' z) G0 J4 O
2 p8 D9 [4 q& W分组group()
# }8 X& N0 D1 }假设test表只有以下一条数据 ( \: X& b, ^/ h
  1. { domain: "www.mongodb.org"
    ! e# s( p8 K4 e0 Z
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    + m- a1 L) q8 N% m; p
  3. , response_time: 0.05 - f/ |/ c  S, [  ~' p( b3 M. n
  4. , http_action: "GET /display/DOCS/Aggregation" ) [6 Y; O7 J$ W2 }
  5. }
复制代码

, H' {: s6 J- w! H9 V使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; # V3 M4 |% [3 F) r1 ?; Z5 `
  1. db.test.group(
    8 a1 ]3 u0 v0 R7 Q7 z. e: D! ]
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    ! ]* k4 K" m3 Z9 I# e& ]. S( g8 ]) v% r
  3. , key: {http_action: true}
    # _3 o" O2 O$ _1 d* ~
  4. , initial: {count: 0, total_time:0}
    / Z7 Y% ]3 \) g" S$ u# ^1 D0 _
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    7 N; K; N: o1 s! I( j4 [) u
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } * @% W6 G2 ^7 |) `- M" D
  7. } ); ! F( q+ Z# p. ?3 N8 y1 P( s
  8. ! L& |& W. S0 [  G) }8 A
  9. [ ) i0 L3 ~7 h+ L' P- Q
  10. { 2 X6 L; w  Y2 W; c5 C
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ; l6 j! N1 e; t& @- G* V% ?9 ^; H
  12. "count" : 1,
    + |0 t7 F) |( m& v0 a: ]' v
  13. "total_time" : 0.05,
    2 O  ]% O3 d" D- r" k
  14. "avg_time" : 0.05
    5 H. \! _: ]! T* _4 b& H, m$ }5 M
  15. }
    $ W; J$ _3 y  f! d$ j- r
  16. ]
复制代码

5 s# d9 b) J9 Y3 m4 j6 y2 j
+ i  `4 A. \- K; i& F9 ^
7 i! f. |% a) N# v3 H' RMongoDB 高级聚合查询
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
    - J" d( C( L3 S
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
- E( t$ f3 F  R* J

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

: i( i; l+ A" \0 P4 u' g9 }6 d5 s& L7 x" g/ V
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

6 N6 r9 {% c0 v4 _4 R, ?- [8 F% n# [$ n  o
8 l0 [( M5 _! d( k7 W) i
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
  A/ O2 B+ I; D4 r! ~+ `- X3 L

8 a9 b( v* }% c
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

+ Q5 F$ X2 U5 O4 K0 |  G
: t" S% f/ N. r: |4 f; k7 W- l
输出如:
  1.         " Z; U" u" l) l- J1 L
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

8 d2 l1 j. j4 H
* ]+ A, G7 Q" V5 Q( @5 s$ G5 q! A: D
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"# @' F3 l5 h& X) U% q
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance". l3 p. C. y7 }9 h4 `9 |8 ?
  3.        xmlns:context="http://www.springframework.org/schema/context"9 F" J$ X3 A' Y/ k6 F
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    ; p, n: O# {& U( `
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans9 y* {: k2 @) C& n+ h2 P
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    * I/ }% A: [% B+ r' [
  7.           http://www.springframework.org/schema/context0 I  M2 h/ s5 o! E+ \% B/ r& K
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    ; |. @; U1 f/ x- k+ H
  9.           http://www.springframework.org/schema/data/mongo6 }, E: s+ [) G  W/ K7 E4 h
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">" c1 G) C9 |$ _  d$ S
  11. 3 j( l$ N, L4 [" `# R
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    + G# Z% V0 ?; c& S7 j. n) Z9 X
  13. , q' U- @: y+ g; F+ y. E5 y3 Y5 E) m
  14.     <!-- Default bean name is 'mongo' -->
    & y+ q, H! P. s; m5 R
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />! s, ^. y4 Q: v; G5 f: c% S. |( x

  16. % j, e. m  q2 {
  17.     <mongo:db-factory id="mongoDbFactory"
    9 z' R: }. T6 s5 t$ ]# C$ k# O
  18.                   mongo-ref="mongo") }! X# h0 y% _3 X- }6 p: P
  19.                   dbname="mongotest" />% A* P5 _% B3 V$ ~

  20. 4 u: x7 }5 Q& b% C% H8 P
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    3 |, ^) P+ ^: d# B3 L- j  U6 X
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    7 h* X, @' x  [5 [
  23.     </bean>$ b9 I: X+ \" o: [7 [
  24. </beans>
复制代码

; m9 C; K. U) `+ J, X- x& N$ `
- m: i0 P  E: U4 L, O0 z, K' [: x8 F9 u
maxmin的测试
  1. @Test/ E* j& ]: {* X6 F' L
  2.     public void testMaxAndMinAge() throws Exception {9 H8 n% u" _" q) O6 L5 |; v0 `
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);4 A8 I( t! Y9 g- s! @
  4.         Person result = mongoTemplate.findOne(q, Person.class);" U& R, U* z- G1 M9 X' P
  5.         log.info(result);
    9 ^/ z1 N+ A3 d! }$ z+ X; A

  6. ' H) r6 Z* |- j4 {5 _
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);1 t8 q' Z1 @8 F, G; `& E
  8.         result = mongoTemplate.findOne(q, Person.class);
    . T- [6 P6 k( t  Y! }$ a
  9.         log.info(result);
    6 X* E- J8 g1 n" s( T+ F6 E! T
  10.     }
复制代码
1 e# c) `. i# ]' y5 {

* M5 ]9 ?) H' `% ^* O
distinct的测试:
  1. @Test
    - a$ S- T7 ?- H1 C
  2.     public void testDistinct() throws Exception {
    . S: Z& d, [# {$ B9 k* k( i  y
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    : m4 r( o* ?  C3 _" f% L, r
  4.         for (Object o : result) {
    ( z3 I! R4 k, E1 w. P# q
  5.             log.info(o);
    ; O; u% s; q( H4 x# m7 K8 f1 d
  6.         }, A* O. ]# F6 C3 L1 ?1 I  e  D/ G

  7. ! b8 }7 ~3 ^. G5 Z5 n5 g, R
  8.         log.info("==================================================================");# A. _/ d! P5 ?; j" K  |  p! G
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));' I& b+ E" E; y
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());! j2 x7 B9 \( l. C" T7 @( F
  11.         for (Object o : result) {! s$ y8 p3 N3 V: w# c
  12.             log.info(o);
    2 L1 _% L7 U  g. T1 @
  13.         }; L5 J5 y, h: A8 e( T0 {, p
  14. 5 h6 S/ ?7 z$ z; v& C/ }
  15.         log.info("==================================================================");
    ' A( y! p' R& ]2 k7 N1 C! E2 R' C! I
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");: ?! }8 Q2 p& ]7 O2 }  A
  17.         for (Object o : result) {
    2 D/ t" H: O+ _3 Q$ J+ u
  18.             log.info(o);
    2 F) H2 i5 z5 y: _8 D( ~  L9 {' Y
  19.         }6 F+ z. d7 ]* Y* y( D9 R0 G" D
  20.     }
复制代码

1 b- F! p1 x' y% L& o$ u5 m$ }( Z8 {0 T7 B9 u$ s& y* r
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    6 l( b! F# L. J. j( q
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678& Q" }9 I# f) w( T$ s4 T
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    3 I7 O! _4 @0 s" h) ~6 o
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654" ?; H# w$ S0 n* r
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    & Q) z% n, ^* h3 N% r' h7 b: e
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo( @( R5 v- L9 o) {  V
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456+ n. V. K+ B) p) X, n
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================; h. y, U# |" k9 i
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    , @# n& f3 I1 E# b$ Q- Y) K
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678/ q4 z% @$ a: W
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789& i% M! v& C! \/ b: ]2 u/ C
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    & {! H3 r& j5 I. R8 \
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    2 p: [, _7 P( \1 V3 f) }+ s
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa& _4 W( [/ N" W% D: F
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    , u: E8 P! s6 i! Y! ]7 R) G2 ]0 U& L
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc) M* I- `+ {% R
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www7 U& t* X# ?$ c5 X; {) {
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx  |: Z6 D4 ~( d
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy% v" |2 w2 K* K+ V& w
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz2 L7 S0 _7 X5 h, [1 d
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr/ x, m0 b. \  }! p( o9 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
复制代码
: Y4 C' W; F  e9 d! ^
4 M7 }: W+ _1 z  V( \% m2 i* D- h( F
这里我要特别说明一下, 当使用了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等信息。
2 A5 Z8 o. C+ H5 W' t6 ^
+ p$ H' y9 l$ A5 @

! b5 `8 f( x% z/ K9 r, j! I5 K8 O
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-20 17:12 , Processed in 0.139501 second(s), 23 queries .

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