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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8845|回复: 0

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

[复制链接]
发表于 2019-7-4 17:21:36 | 显示全部楼层 |阅读模式
版本一:
/ v8 t" l" Q. V
' k# k0 U9 f- q1 ) . 大于,小于,大于或等于,小于或等于$ L% Q, S; k- p" S- @

' I* @$ D5 z4 z% u% z7 Z$gt:大于
$ ~* l; D  A2 K$ z& d$lt:小于% ^8 W7 }" ?7 P) F3 e& |
$gte:大于或等于" Q! s' K( z* W' T3 w  K
$lte:小于或等于
7 p) M) I1 T, R  B' o/ z
6 \" Q3 H0 b/ R4 z1 O9 [) ]. ^例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value& I7 d/ K% I( q
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value+ Z) |$ n5 k: Z5 [7 Z, ^
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value$ Y" k4 |; W0 P( L
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
8 K7 _5 o, H& v. ^1 V, M& k
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    ; b/ a+ g- W( O
  2. db.things.find({j : {$gte: 4}});
复制代码

3 l' F; {& R) u+ [* t. k7 r, Q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

9 p: J: B) N* ]
6 l/ ~4 T4 n. L3 q4 d% k
/ l+ I# b. l8 l  J) ^9 B
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

) I( ]1 o1 Y4 N- R2 M# _2 }9 s
3) in 和 not in ($in $nin)
/ Y/ u; L5 H6 H6 v% r6 K
, x$ q1 {( J: [) I' y$ c( Q% ^! ?语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
* H, l! a. ~' ^) L5 }, r4 v: f
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    5 L' }  a/ T- q' ~7 j! v. V% B1 J
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
  j# r3 s" U0 _9 E6 w$ Y# \
3 e' i1 h  W* E; o# g+ o+ u( v
4) 取模运算$mod
8 J' F7 Y: F! d$ x, ?3 [9 ]6 R- }8 E- L; p" W' X5 H
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
; J; {7 [! b, t1 H: B4 Y
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

9 A% E1 B; C2 F. q. F' Q% c

0 U( d; n- L( m! D  D1 t  g5)  $all
2 @3 ^4 K; v8 K+ o6 u, v6 z# h5 r) O8 q6 }4 S% Q
$all和$in类似,但是他需要匹配条件内所有的值:( Q8 a6 L0 h1 u6 T. q7 @4 C

8 l$ t* X$ p7 g, @) g0 r如有一个对象:! W, _+ D2 j6 j
  1. { a: [ 1, 2, 3 ] }
复制代码

& J0 f( I  w" p9 g6 B7 Y
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
; ^) o, M: C& V0 X3 y
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

. c0 l6 N$ a  j7 I* u
$ G4 G" n. u9 z
6)  $size- y) [, ~& [9 S) _2 ]  ?

" j! k/ B" K% h' d/ }7 G& k: W+ z3 T$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:. l% i3 |5 u/ F) f" D& ^6 v  t

* I' y, L* y2 v4 G下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
) A9 r" I5 Z4 w
官网上说不能用来匹配一个范围内的元素,如果想找$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.
3 g1 e, r8 f2 v# |- j* k5 `
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回# h0 v7 G' f6 e. P- L4 ~& @* N
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
1 m0 N8 Z4 k$ `
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    ' U. g5 j! O& u9 v! |9 X( Z
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

9 r0 V# B1 i1 o* `
9)正则表达式! e6 P* m1 U0 J$ g6 T' P
; Q+ u* E: F# x" _
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

& O0 N" {! B; m( ^
10)  查询数据内的值
' }- }% i1 z, V- {. _& [3 p
3 Q  I$ q3 |3 Y1 [下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

4 I3 t; B6 s7 @1 Q/ S6 H0 H. d, x
11) $elemMatch. p2 W) C- g" @. P1 }: ^
/ B* u* W& F( @9 P9 L* X' V
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    7 x& V- _2 O$ y1 _  K1 C* y. F6 i
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    ( d7 G; B) e# U8 y2 ~
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]8 M* z5 Y% I1 C0 w. Q
  4. }
复制代码
  P1 x6 |2 y5 U  r* j7 Z
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )" i8 V3 I5 E9 N% v  X+ ?
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } & e7 f! u/ T" b( I$ X3 |5 Z
5 g, f4 D& q4 a* v8 B4 S0 y7 w8 R
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

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

2 a: j2 ]( \5 T" d* f
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
- {3 C; l9 ^& ^7 `
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
1 A. q* A# T5 I7 J6 ?
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

) z1 Q2 x$ H3 y* K
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

. ]& c" e! i+ [: O7 O. m: @1 X6 T
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    7 O, e" ~! l' f3 H5 n8 M
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
2 V7 n- n/ o! t
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
2 o( N4 U) I, M! |( U, [# C
. r- U+ B  b4 _. d# C+ jmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
& `* N8 j* Z, G
7 `7 `4 v% H% _' k" n0 Xhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions+ @4 T5 }$ N1 t4 S7 D: m
2 ?; q# q0 k! q
版本二:0 [& s7 f3 k. f. V, @/ e
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
- J0 M& A# N9 v
  1. use admin
复制代码
4 t7 I7 J1 s) O. H
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

; b  W$ O' T& R+ g6 ?
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

6 m- k  x( `0 B" Q0 z
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
8 p" |' D2 U; m" i! y
         5. #删除用户
  1.           db.removeUser('name')
复制代码
0 }+ _0 H. c! M- ?9 H" [* D
         6. #查看所有用户
  1.           show users
复制代码
* g  w/ e0 l* k8 j8 ]
         7. #查看所有数据库
  1.           show dbs
复制代码

  ]) W, _: F: m7 N) Y
         8. #查看所有的collection
  1.           show collections
复制代码
/ S2 K3 W! v( r
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
& w0 N3 Q6 r4 t) O+ e
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

9 h+ [% `6 S" U5 Q% J" x+ v% A
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

0 a% M2 y- [9 k% U- X% x- @) h
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

# s5 f9 T; v9 z. q8 i8 P, Y" C4 F
        13. #查看profiling
  1.           show profile
复制代码
" u; m6 E/ F7 s6 r
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
8 W, Y  p- V' Y* e) `7 ?) B
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

, Q& _' }1 L, J1 m1 P4 W8 k6 m
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

% n- F! {6 E2 @" m5 h
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

/ z4 C7 d) z: T4 o1 l* o! Z, P
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
$ U& Z3 U$ N7 i3 o. L
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
- m8 T* E2 s, H- q$ ~1 C" s
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

( K( ^7 w  Q9 q- l
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
* ^6 [0 M+ A# d" Y, u* d
   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()

3 {: t2 |9 {3 ?0 B2 ?2 U
6.  高级查询
条件操作符
) P, g7 W& U, K/ f* g: K% q4 B4 Y
  1. $gt : > 6 Q. [5 t* o) Q( h1 B3 V
  2. $lt : < 8 S: n; ?  y! a$ `# ~( ]
  3. $gte: >= 0 x# _/ M- w* ^: b5 d
  4. $lte: <= ; h9 A7 A* F9 U, m
  5. $ne : !=、<>
    : L) W; s) F  T2 d  o
  6. $in : in 2 B* H2 U( n1 i2 q
  7. $nin: not in
    ) X, X/ E# Q1 _: q( R, ?% n
  8. $all: all 0 A# N: [% H2 O& O/ n. G. h2 [
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
% _8 H! [  \9 c
& }/ I% X+ E* m9 d6 Y7 b
查询 name <> "bruce" and age >= 18 的数据 ' r$ E, W! R  \- Y; k. t3 b! K
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

) A/ l0 ^) s+ w) |5 w0 G  c* [  v- F- D3 H/ x+ t) F5 y
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
- R3 P: ?0 F! g; {/ B, K2 g+ H6 o4 P
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

0 J" e; L; m+ V; Q7 i( e6 A$ a  x+ |- h7 C9 u: X
查询 age in (20,22,24,26) 的数据
& _& g. t- l$ ~: B5 u1 n
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

- u4 C9 h; O( @# T- r
/ \6 O$ E; s+ H2 r! W查询 age取模10等于0 的数据
7 K5 o& o' r5 s2 Y1 o
  1. db.users.find('this.age % 10 == 0');
复制代码

- h* y+ i: b, J! D2 B或者
. B' @# V6 H/ I$ J6 b, Q  v' V
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

# o2 o. l, r# u) S6 z3 {& C7 a8 F  j% c7 E( T+ t9 l4 N
匹配所有
" D) h  W4 M" h1 w7 N3 w
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

0 R$ s' E8 f8 w可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
! ]: p. p7 N9 W2 {8 v# s可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 0 Z3 \3 y+ @$ E
/ c0 {8 b2 T; J, T6 {
查询不匹配name=B*带头的记录
+ d! M$ A5 Q  T, q
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

# s4 [5 d0 N6 R% {$ M查询 age取模10不等于0 的数据
/ B6 @7 o3 v; v& W  R
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
0 [0 ~- h, p; ]# S

3 y% o6 f0 d, }3 y#返回部分字段
7 `' [% K4 C8 @$ k4 K选择返回age和_id字段(_id字段总是会被返回) - {( u) H  ?1 o% G$ B1 D6 u
  1. db.users.find({}, {age:1}); 5 }2 o7 |- d% K/ q* B
  2. db.users.find({}, {age:3}); , S( H. j' ?" ^6 r4 H
  3. db.users.find({}, {age:true});
    1 _7 h! e: C8 g3 f- Q+ k5 f' z9 u8 H
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

$ R8 Q! C0 ?. a. B/ ~6 c0为false, 非0为true ) t4 U/ w7 I1 ~* o8 G9 G% ^3 X: C, R
3 t# F- J9 t# k& h) t$ F
选择返回age、address和_id字段
/ |1 E+ A# V" V; d# F, J
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
% @$ i+ p3 n. }+ C

; Q1 E& a" |/ _+ U# q排除返回age、address和_id字段 + f/ `0 B, f' B  }, X
  1. db.users.find({}, {age:0, address:false});
    ' t' [. u, J' @# W5 w9 N  [
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
; q; b0 |" r/ u  B+ u
* v% I& B* S% m9 ]; q" L
数组元素个数判断
  h4 T$ }, P0 C9 l对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 1 ?8 c6 r9 j4 K; o3 |
匹配db.users.find({favorite_number: {$size: 3}}); " @3 q: o4 u! z6 S
不匹配db.users.find({favorite_number: {$size: 2}});
2 S( X; M4 E. K+ H0 o1 Q' ~" e: J! t- Z+ K1 {) \: T
$exists判断字段是否存在
3 ?* D. R, w7 F3 t2 M查询所有存在name字段的记录
) K+ @* w+ z+ `- w
  1. db.users.find({name: {$exists: true}});
复制代码
. B: Q6 g2 \# {: S( ]7 @: |
查询所有不存在phone字段的记录 4 h+ D; J7 J" G/ V3 v
  1. db.users.find({phone: {$exists: false}});
复制代码

. I; O6 b1 ~1 |8 j0 H
# u9 n# v9 C' d) t6 p) r$type判断字段类型 " J1 Z. j" I* S# d( P) b( x
查询所有name字段是字符类型的
3 w& G1 r3 M/ }( d) e/ E6 g
  1. db.users.find({name: {$type: 2}});
    ) w$ A: V7 _4 W  u) S
复制代码

8 k; u8 B. h# j0 s  m4 `  q, a$ J查询所有age字段是整型的   ^) y7 X2 ~3 y$ @" J- R/ z( X
  1. db.users.find({age: {$type: 16}}); ) f* u4 u0 h2 Y- A" }
复制代码

8 d' m: K! ]7 U) z( h对于字符字段,可以使用正则表达式 % P- G: m/ {2 D, @9 \- Y% m
查询以字母b或者B带头的所有记录
/ x7 H! z2 Z& u# c# Y
  1. db.users.find({name: /^b.*/i});
    3 N- N! @% [/ w: B
复制代码
# f( W4 a9 q9 i" w
$elemMatch(1.3.1及以上版本)
% e. M9 _7 `* b. J为数组的字段中匹配其中某个元素
8 b. k+ D! f+ F1 r9 `9 ^6 s5 x$ o; Q  u4 Q& j1 s
Javascript查询和$where查询 - O2 S3 N, y) g; x2 [) r
查询 age > 18 的记录,以下查询都一样
) p, l7 q5 h& f6 j, w
  1. db.users.find({age: {$gt: 18}});
    ' T9 _$ o: L$ E
  2. db.users.find({$where: "this.age > 18"});
    0 D/ D0 I* e1 ~! p% _' }+ E% R
  3. db.users.find("this.age > 18");
    % j0 i7 n9 ]% \1 f' s: h: v
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

- W3 A, B9 t% W4 E% O/ t7 h$ {' }1 `# N) F3 \1 {9 F' }1 Y
排序sort()
! J1 P! e& F0 v" t$ I' T以年龄升序asc ; r0 G4 b" F( h
  1. db.users.find().sort({age: 1}); 6 H0 x5 O) \6 v) e2 |
复制代码

; y, r! p$ g+ ~- T* U1 I以年龄降序desc , B/ h# [" [% X. y
  1. db.users.find().sort({age: -1}); 4 K2 X0 H( C- Z3 h
复制代码
3 P2 ^! Z* S" j" [! }
限制返回记录数量limit() % F4 X3 B* I8 N" O/ a1 L. x
返回5条记录
, w; [& P: f6 r. h* E! L6 s
  1. db.users.find().limit(5); - {! r5 H/ }9 M
复制代码
; t& k3 A! f, J- B
返回3条记录并打印信息 1 D; L6 Q; i  w  f1 Y
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 6 @( q, y! G8 e( T5 Z
复制代码
! v3 K8 c, e; d- C& v
结果 0 d& P9 O; z; e6 C" `
  1. my age is 18 8 P5 k* ~/ `  e" c9 {# O
  2. my age is 19
    + E: S1 M2 l. g: Z8 m7 g5 d. M
  3. my age is 20
复制代码
; s" a( J4 M$ {6 b2 c6 ]4 v

, S$ L+ _8 \( I限制返回记录的开始点skip()
3 ]/ M& E6 q% `从第3条记录开始,返回5条记录(limit 3, 5) 5 G$ K- S7 C$ _' c. z3 v
  1. db.users.find().skip(3).limit(5);
    - L8 ]8 W9 W2 g0 I
复制代码
( H, F! H4 Q% r; f' H" Q7 \
查询记录条数count()
2 l7 K& Z: w$ f# {db.users.find().count();
0 p6 w. F$ Z, `* h- c$ _9 Jdb.users.find({age:18}).count(); 1 z3 o) h( A" {& E
以下返回的不是5,而是user表中所有的记录数量 , R4 Q0 I8 o3 Y) V) ^
db.users.find().skip(10).limit(5).count();
' c8 D* F: T6 Z2 ^' f如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
" C4 x' \2 U  O6 a
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
% A* e$ X, t- R7 r8 m, o, e& R
2 d! u' Q0 \4 w9 d7 }
分组group() ; G0 k+ {) U) K  U' K  i
假设test表只有以下一条数据
% A" c3 N* Z7 ~+ I8 m
  1. { domain: "www.mongodb.org" , Q0 h: i9 d; A  A
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} * D  Z: |3 N8 z
  3. , response_time: 0.05 . V  M' k% R3 I: t5 S. ~& Y
  4. , http_action: "GET /display/DOCS/Aggregation"
    5 }6 H! j1 S2 |) V7 v( q
  5. }
复制代码
" @3 c2 Y& _, V3 X
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
7 f3 b  L% M$ `2 J1 s2 d$ F9 Z' R! P
  1. db.test.group( $ ^& A6 @4 h  Y$ H$ D/ [6 ~
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} , \) ^, P. n6 ]; {4 A& e
  3. , key: {http_action: true} ( ^! j1 g" Y( F7 ]" ^$ I. [& Z/ m
  4. , initial: {count: 0, total_time:0}   T. \" D' ?: I  V$ L" H( Y8 V
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } # T) k* x4 \! `
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    8 w9 K/ E; |1 Y* T) l; u  v
  7. } );
    ) Y9 {1 H" |/ t& m* i
  8. $ b; L; F" ~! d, k0 i, K
  9. [ 1 z8 L1 c' T% }- C
  10. { 0 B8 m/ _3 k! {  b; m" A
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ) A$ f) h' f  \+ a* B% C1 d
  12. "count" : 1, + ~! `; o: s; r  i* m$ Q
  13. "total_time" : 0.05,   Z( N: e6 t- b* I6 Z+ ]# w
  14. "avg_time" : 0.05
    8 [3 V8 v7 J/ `( Y/ J3 A
  15. } ' E. v. \8 S, _" h: K
  16. ]
复制代码
# v5 L% J7 Y) x$ Z  S$ `
3 o) _: _# ^) O1 g
; e" r0 R+ P7 ?( P/ u
MongoDB 高级聚合查询
MongoDB版本为:2.0.8
系统为:64位Ubuntu 12.04
先给他家看一下我的表结构[Oh sorry, Mongo叫集合]
20121225152152_182.png
如你所见,我尽量的模拟现实生活中的场景。这是一个人的实体,他有基本的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 和Min0 g; G% e& N1 h' W* n6 w$ G
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
1 H1 m$ T; T* A! d

9 u" P, X! Y5 G
  J  V0 k# f; m4 ]! Y
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    # S4 a+ F! s3 d. W) g6 u
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
. X, C! ?; g' F! B. T2 k
& a5 c( m! r1 W# p( u: h3 ]
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

$ T: b& t* E' `' G2 p# e' j
; E9 |( x% J6 ?! }1 ^
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

: ^; [7 M9 Y( u7 C0 ]
* m3 w6 h. w+ B1 B8 T0 t+ g
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

/ ]7 x8 r7 \$ ~1 c
6 k6 `7 E  W8 K6 ?; e" B
输出如:
  1.         
    / ~  J/ r& l* [
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
8 M( G( V: ^0 d% {, o
% G" ~% ]  P, }' V4 g0 W8 d( h! V

9 m* c& m4 k5 J% q8 p  K
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    8 K. p  p: Q/ |  ~
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    , v" Y; [- ~# u% b1 T6 Q
  3.        xmlns:context="http://www.springframework.org/schema/context"! j' @/ i5 N4 p6 p6 |4 U
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    ; @/ h9 @4 Z/ j+ B1 G" R& F
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans) v* m! T/ J. }$ C- t% w
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd2 t# g% D  H) t1 G" r
  7.           http://www.springframework.org/schema/context
    + U! G1 ]6 d: A1 Z, o1 i
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    * T- q! e, `+ L! i( K# e& E
  9.           http://www.springframework.org/schema/data/mongo
    / u7 U0 W6 `( B% }; v
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">% w9 G3 H- K. [  V0 v% e3 H9 F+ ^
  11. * s( o5 s, y0 ^! n9 \
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    : X1 C- m4 b4 J* {9 }: S0 s2 B; B4 m5 L2 A
  13. . y/ g5 Z( z' U, ~# ^
  14.     <!-- Default bean name is 'mongo' -->
    $ Z0 B6 M5 S+ w
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    9 V& B) F4 w9 ~/ V5 @$ m; |
  16. ( K1 ~' S6 G) K
  17.     <mongo:db-factory id="mongoDbFactory"
    " i3 T4 {4 C7 W9 q. f% v
  18.                   mongo-ref="mongo"
    $ E' l+ ?2 V) M9 e
  19.                   dbname="mongotest" />
    3 w- p1 N9 w/ ^9 |: V

  20. + f0 x* ^9 }$ Y% Y7 f! c) Y: m
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">) G) c2 g* C  k
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>$ L/ [) H4 D4 j. Z4 ~/ u: p
  23.     </bean>2 Y) G2 S% _1 H" }+ V) a$ J; L6 ^
  24. </beans>
复制代码

5 p! r+ {% O' ?3 Z" n

8 }; }% n+ x% S5 D9 B( j5 r
maxmin的测试
  1. @Test' l1 K/ i9 G; K
  2.     public void testMaxAndMinAge() throws Exception {
    ( Q  \* Y7 z' o1 S2 B' t! R8 }
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    ' R1 U1 h/ H7 z7 E1 Q
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    9 p! m3 ]9 V: Y# h) `/ D3 K6 ?
  5.         log.info(result);7 Q% {0 E5 g! C4 C! [+ R
  6. % ?3 H  Q/ G, T
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);6 V% T0 g" R- n: a# [5 K- r. t8 n: F' _, M
  8.         result = mongoTemplate.findOne(q, Person.class);3 J4 g0 ~# g3 _5 I
  9.         log.info(result);, C5 I. j6 g/ c7 k# I; `
  10.     }
复制代码

# n7 J! }& Z; z
$ w5 a, V: i" P" N+ C
distinct的测试:
  1. @Test7 I# u6 \, p+ c4 q' K* e) H) m
  2.     public void testDistinct() throws Exception {1 e% a# A4 K& G/ d/ A
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");' W8 e- q2 _1 |0 `6 l; {' X
  4.         for (Object o : result) {. V2 ^3 K4 U0 z" a5 V  v0 z/ K
  5.             log.info(o);- {! y* Q8 l& k* v
  6.         }
    $ ]( {1 J9 L  M; n% m

  7. . o6 G& T5 P5 \) A) ]  m
  8.         log.info("==================================================================");
    ' h/ M% D. H  r! z( F  h
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));- k) Q3 J, T- x+ c
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    ) t% ]! r7 d+ F' ~. R3 L1 W9 D0 x
  11.         for (Object o : result) {
    0 [7 t' e; E$ D
  12.             log.info(o);
    + I7 s) I% a) M' q$ a' N3 M/ I
  13.         }! D+ x' s6 |( N2 p0 X+ q# n5 K

  14. , j4 }- [- c" e+ [& ?% Z
  15.         log.info("==================================================================");( y9 E" l5 T2 \  U
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");7 A8 M6 R- Z1 P9 L  i
  17.         for (Object o : result) {
    4 N% \! N  N0 L$ C! [' e- L0 \
  18.             log.info(o);
    ' n1 \* C4 J  s8 U+ [) B! e4 V
  19.         }
    + |3 N2 W  S$ n
  20.     }
复制代码

* ^- M) D- o  D2 Q
$ g) x% m9 U1 [2 _4 n
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    / D6 X; c8 i& p0 @) P/ H, f
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678/ u: C: |3 H4 Q; w! H- H. D7 {. f
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
      L6 B8 z% C1 K. [+ }5 U: d
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876541 i9 `$ H! c$ Z7 ~" `
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni! u  ~5 v. ^0 }% i$ [
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    7 U4 ?1 W! E5 R: o1 v, _
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456% C, O  S' I' a" d! H2 e
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================( ~- c: h& K% M8 M0 x+ J" s
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567) F- k  u. d9 t# k( n# e0 {- s1 V
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678" R- O6 p5 y4 n, k; [4 l1 x
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    6 D$ z% ?6 j! z5 q7 H2 |
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654' v; N; E! j2 F7 k) I
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    2 ?4 m, a  Y' o8 s% q
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    " s: I- {. A! r! P* r
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    1 c% Y9 S! T% C& B
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc; m2 R5 k! H$ h" Y# g  V3 Z- j
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    5 }% P* _# |: ]" |, t" n
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    * }8 q5 j6 H7 X6 ^% R9 O9 w
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy7 O( b) F/ R  j# A% f6 H
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz4 T3 g0 |; U/ j
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr: _9 Z- a3 K8 L7 a. g! x
  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
复制代码
- o0 {, p+ l8 [
& h3 L$ ^- F7 y
这里我要特别说明一下, 当使用了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等信息。
% }/ E, A2 ^( K. J/ C+ @+ F
) x7 W7 S2 c9 A$ r0 O7 `4 n; \3 c

* K" O. {* E# g" |9 L$ ~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2023-9-30 08:43 , Processed in 0.137974 second(s), 25 queries .

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