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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
版本一:  f# `6 ]# [* o0 v" |
5 A2 L# j& s* U
1 ) . 大于,小于,大于或等于,小于或等于
' U) z# J: v& U3 A( @2 i  H4 V* M* C( x: w/ k2 R: R
$gt:大于) z1 N: v# ~7 @
$lt:小于
+ i: _3 L! O( w, Q$gte:大于或等于
( k- c5 k" o; Z4 Q$lte:小于或等于
; e: W9 y, l! g
& Z; W. ^" ^) P例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value- W: [$ I3 x  _3 t3 B. f
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    6 }3 Y0 P( r4 W, ]+ [3 b
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    " }1 Y1 g. s5 k6 d% b% L
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
/ d/ j  ^9 ^# R' k. _9 E
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});3 d. v6 y, ]$ F5 l' e
  2. db.things.find({j : {$gte: 4}});
复制代码

2 k4 c1 U9 d& B- \6 q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

9 y( k9 g% G$ O! {5 u1 j7 [: _5 |# n/ t+ [  g
# H( H+ Z  A( p  z$ E# K
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

- i, n: d  e3 u4 `2 x
3) in 和 not in ($in $nin)1 w1 f# O% ^, e

) Y: B8 J, {: F/ ~# G+ E+ i语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

" |' y4 T! |) j+ Z6 ^4 t9 r
例子:
  1. db.things.find({j:{$in: [2,4,6]}});3 M% O2 V6 E) W) T" i0 n' w
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

: x$ F$ J6 ?; ~! o$ A$ z  @
# Z, V  [* X* {+ i9 w/ O- g+ ^
4) 取模运算$mod
0 g# y* Q( ~  m$ \- m4 X5 U' L8 p5 N) R" P5 P6 V
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
! \6 b1 {3 k$ k
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

  s. f! o/ d2 x5 f$ K6 N3 v1 F
; M- n9 a" z3 O% G' V4 v# c6 b4 s
5)  $all  a( h1 e, q1 o( L. x/ t+ q; t! X
) I) U! |1 c$ U
$all和$in类似,但是他需要匹配条件内所有的值:3 J2 ^6 ~! o* C0 l; o0 B  ?0 ]* A
6 g2 e9 t6 S" c
如有一个对象:
# M* f- g3 W2 V7 M
  1. { a: [ 1, 2, 3 ] }
复制代码

1 u8 |7 x6 b1 l/ V
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

& A9 R/ E0 Z: s- c1 l8 y7 m
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

) Y0 O/ I) P1 v- m

' O, F; A" }0 ]$ U/ ]4 ?# [6)  $size' Y: D- }+ Z) c. q* E7 v( Q" H
5 i6 o8 h# g4 b+ v
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
, h5 ]# N( k2 p; K/ D8 r+ e6 ~7 m; C2 p1 A: ^
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
$ q4 {3 c7 V8 ]
官网上说不能用来匹配一个范围内的元素,如果想找$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 h0 f" D8 L$ R" \
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回' @0 ~, u. l; w) C" z' L
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

4 c& v4 }! A% X' F1 z: ^8 g
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string5 c+ N9 g) }1 _# m' N. Y' B
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
2 P% L# y9 Z8 M; u6 ^9 L# ]
9)正则表达式
8 s# p+ A* |1 n& l8 O
7 o0 K/ X, D' l9 V& Q# z$ ymongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
" w# `( k: C/ L% n  @0 B
10)  查询数据内的值1 D2 `8 N: B, q' I

7 ~' x6 @! G" |+ r* J/ d下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
/ v& n: K3 S: P' W0 T& X- K/ o! X
11) $elemMatch4 G9 p: l; f/ k
* J: l6 _* L2 l- m! [
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) ' p; }0 u# E" R& E
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  0 F& o: k" i$ |" v$ T! u
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]1 h8 n% v2 b  T9 s/ g# B
  4. }
复制代码

: L8 i& ]2 ~- y- |1 W  f$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
; E6 J0 A4 A3 T; L1 _
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }   O( w- v% I6 R8 f2 [) Q9 C, I3 n
% k- Q* M2 g9 ]+ ]( `2 f
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
. q: @9 E2 Q  U; E  @9 K4 e: \3 U
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
! f" @7 d( n$ D
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
4 a* {. Z7 d8 V, G5 n
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
* U" g; \* l' ]
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
0 _% Q$ x% |6 j7 h. h( e2 K
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
  o/ k1 S/ t3 s
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );" T* \( H* s* i2 c& j- _8 |
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

3 w% j+ v! J3 g4 F
mongodb还有很多函数可以用,如排序,统计等,请参考原文。: o5 N3 j" C6 F6 j/ S

$ [9 O# i$ G! v  m5 {mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:* Z7 i# x1 V1 o- W- v1 n
- r$ r9 k- B$ `. {
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
8 v6 z* U# y% e8 c3 Z) C* o) k  V
版本二:
: [& G1 B9 @( I) R1 G, z. E$ l9 ?  M
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
' C. z2 R: n  }: T
  1. use admin
复制代码
4 D5 T9 A) A  T6 e6 ]# I7 p
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
# l6 c: I8 t0 ]& v. [% u
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
) D* a: E$ {: ?3 v9 A3 ^" J  P; }
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

" U* R2 C' k1 e+ W; z" n- \
         5. #删除用户
  1.           db.removeUser('name')
复制代码

5 `, `# h: N, s7 h
         6. #查看所有用户
  1.           show users
复制代码
+ \& R$ R7 n" i( ?% p0 |; e
         7. #查看所有数据库
  1.           show dbs
复制代码
( L5 ?$ u+ j$ D
         8. #查看所有的collection
  1.           show collections
复制代码
: c+ |; i' U2 N6 k9 Z
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

, b4 Q" W+ Q: J5 X9 A- d
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

* L/ C$ P% I9 q! V( l
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

9 d5 M) B* I5 @+ F
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
, j3 q: |7 h6 X* f6 g
        13. #查看profiling
  1.           show profile
复制代码
# h& u$ W3 L2 U' F+ p+ L
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

, b, X+ c4 g" v( U$ P
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

! `  V  @' `) O8 d. \
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

9 X5 U4 |- H7 R, y9 F' A
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

& S. d* n/ o; {; a) V. N
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
' G3 x2 Q* l/ N" y7 |6 k
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

* |" L- |( K, v7 T6 c& o7 d
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

7 t4 A3 S$ P$ M, T" }; I8 M
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
! c# |& D7 @% y, s: ~( g  l5 M
   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()
5 c' a4 S. M8 @* k, a' I# I8 Z
6.  高级查询
条件操作符 * o7 }& v' f0 a8 b3 ?6 Q
  1. $gt : > 7 r: A9 f& S+ ~  l& ?0 S
  2. $lt : < ) q2 ]- A' `/ J/ S9 g2 `
  3. $gte: >= 4 a+ j4 Q, Q, p
  4. $lte: <=
    3 n8 W' ~8 Y4 p; r9 a& ]
  5. $ne : !=、<> * T8 Y& v. D7 ~: P5 B/ N; t" L
  6. $in : in 6 F: M" ~1 O; Q
  7. $nin: not in $ \1 G) T6 B4 T6 g
  8. $all: all 6 T9 s- J2 A" m3 A3 Z  B; l% h
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
  c) Q& Y0 [  C: ^8 Z/ ]. J2 C
6 K0 x, Q# k- \: E3 E. G$ [* A
查询 name <> "bruce" and age >= 18 的数据
/ W: b7 ], j% T4 c0 e4 Y1 `" N
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
% @  J+ A4 p$ X, k' Q% V

, E) V& V8 f! `8 ~查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 - s' f' S1 k4 [! N
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
; r4 Q/ a' |$ f) i) h4 |, C* C

% ?; P; z2 N, C8 i- E: H查询 age in (20,22,24,26) 的数据
7 T/ h+ M1 l7 ~" v& T
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

  U0 e( k- o+ [* w4 e8 Q; F! e% Y9 `4 u$ i3 ^
查询 age取模10等于0 的数据
& Q* T9 f4 y$ X! S& l( O/ n( L7 E+ W
  1. db.users.find('this.age % 10 == 0');
复制代码
. S% T! ~7 G9 L' Q
或者   J2 J" P2 u2 ~5 H/ V
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
: X3 a: ]6 J' b% v9 W, j& c& L

$ }% |- z' W( B: s匹配所有
  a$ J3 q: ~: [' g, W7 w
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

( \# t' x6 B. v/ t" X& D' I可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } - W, |& D6 q2 k& M6 ?
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
+ l) u7 T# D: e
( e7 u5 n! ?5 ?  V2 n( O查询不匹配name=B*带头的记录
" c; E' r  h5 Q! I
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
! M4 M# [' ]! N# j* s/ H( S# `) n
查询 age取模10不等于0 的数据
/ M. {0 W, V; q' v. n
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
- l3 \: g7 l1 {! n4 c6 r/ k8 s5 d
# f- d5 D, B+ c4 x9 f
#返回部分字段 8 s4 @6 [6 g, X8 @% |+ N/ w" B1 e
选择返回age和_id字段(_id字段总是会被返回)
: a4 N* P0 H* s; [
  1. db.users.find({}, {age:1});
    3 j$ w8 ^% x7 J" K* d  _' h
  2. db.users.find({}, {age:3});
    ! d4 E, U. s2 E! V4 k$ l' L$ @
  3. db.users.find({}, {age:true});
    4 b8 z" O  o! \  w6 B6 F2 V
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
7 _/ [+ R6 S" B* C; ]
0为false, 非0为true
* P7 e; k" W% x# U& o
2 z. [* ?3 |+ _, x$ l+ Y" V选择返回age、address和_id字段
1 P0 E+ M6 A$ P
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
, Y6 t3 H. z; L8 m

9 q7 w; W; C6 _; |% \排除返回age、address和_id字段 + l6 I. Z0 B3 T* P/ ]& G
  1. db.users.find({}, {age:0, address:false});
    ; P  }: t8 T+ X
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
) Q+ Y* O; o. q0 m- l; O. {

( T  J; _/ X1 j数组元素个数判断 - `3 D. {- l$ w0 M7 o
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
1 S$ q. a/ l+ ?匹配db.users.find({favorite_number: {$size: 3}});
* [5 K9 l7 s% C6 q+ C, Y3 _" c不匹配db.users.find({favorite_number: {$size: 2}}); " d5 Q! q6 b/ `& n

( v" ]. L- M  T+ I  y' Q9 h. u$exists判断字段是否存在 5 `- \# U1 C! X. L+ v/ @
查询所有存在name字段的记录 " h. v4 N1 Y, O+ _8 e3 M( O
  1. db.users.find({name: {$exists: true}});
复制代码

8 }2 e5 i: ?2 c7 e# J2 K+ n查询所有不存在phone字段的记录 ' A& ?. ]% C: l
  1. db.users.find({phone: {$exists: false}});
复制代码
3 A; f1 j. r3 d- d+ x$ ]/ W
- O6 X7 M( `1 K
$type判断字段类型 3 Q0 |7 r9 u) e! R3 S& g9 W2 q
查询所有name字段是字符类型的
1 l, c; t  u0 R9 t% {
  1. db.users.find({name: {$type: 2}});
    0 r/ `4 f3 l& V4 l: A
复制代码
- X! \. K3 u/ R* ~. g5 p
查询所有age字段是整型的 % C2 E$ M1 N7 g7 {. ]$ J
  1. db.users.find({age: {$type: 16}});
    ; W% D0 @( X. ~. t7 q
复制代码
6 K- Z1 e3 K6 y4 m
对于字符字段,可以使用正则表达式 / H3 x. H  o  N& y& `# A5 C
查询以字母b或者B带头的所有记录
! I  R" ^! C8 h3 s% d
  1. db.users.find({name: /^b.*/i});
    " u# o  D: z7 y$ x; g: y  @
复制代码

& N& w& e) {& A$elemMatch(1.3.1及以上版本) ' c5 x! K( D7 p  n3 S( e" U8 i
为数组的字段中匹配其中某个元素
$ M4 n& m# C* y7 k! U4 M
9 f1 d0 i% [* i9 K( E: T7 [4 pJavascript查询和$where查询 6 F8 E7 r0 Z7 H& T1 V0 P  @& m6 ~
查询 age > 18 的记录,以下查询都一样 1 e; V8 }  N8 `4 |
  1. db.users.find({age: {$gt: 18}});
    ( Y1 w. p4 W: O) h& e
  2. db.users.find({$where: "this.age > 18"}); " ]- F2 l. [2 [  q
  3. db.users.find("this.age > 18"); 4 e! E: r* a% z1 F/ e1 X: c. f2 I
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

. z& G3 r: g# {; d* Q* o. G
& \* }. n+ U$ o+ P7 \排序sort() 8 X6 L8 ?6 b% f4 e  N2 p/ z
以年龄升序asc 7 e6 b/ O( I0 L; c5 S4 a: k
  1. db.users.find().sort({age: 1});
    8 X  W# H4 L( Q% f. h# d. w
复制代码

3 G& S) j" E5 g以年龄降序desc
+ _$ a' ^% Z3 G7 J
  1. db.users.find().sort({age: -1}); - c8 C/ h5 T  m* Z
复制代码
4 x$ ^+ Q2 o/ b- L
限制返回记录数量limit() % B7 z- G+ Q, b" ?, h1 H
返回5条记录
( V* f. U- k0 `* p$ y
  1. db.users.find().limit(5);
    $ u9 t3 x. j$ t( c  q9 o
复制代码

$ v) Q$ G9 @$ n/ Y4 r返回3条记录并打印信息 5 z  L0 S  O' G7 S1 N
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 3 B& C) T! B, V
复制代码

0 a3 x- N% K$ [- g' T结果
4 w8 ]' P# J$ b3 F4 I- l  N
  1. my age is 18
    , H+ m# Z) W% ~' e8 J
  2. my age is 19 7 e% R. g+ Z/ L3 y
  3. my age is 20
复制代码
0 ]% w4 ?9 |9 f  H

$ @- y" K, M  t* ]3 Z2 ^限制返回记录的开始点skip() 1 x% ]+ n3 J9 B9 \" I
从第3条记录开始,返回5条记录(limit 3, 5)
' T3 X4 {1 ]  \4 i1 N
  1. db.users.find().skip(3).limit(5);
    7 p2 y# P0 L% S" A: V( B+ D
复制代码

4 [. m9 Q# F9 I" n; ?: m查询记录条数count() 5 O5 ^8 I! ~, e7 u1 p' J
db.users.find().count(); / h) J$ w: D; U" F9 x& q; y( h- `
db.users.find({age:18}).count(); ) ]/ }# z1 i3 r
以下返回的不是5,而是user表中所有的记录数量
* X. z5 b' R% ^. D! \db.users.find().skip(10).limit(5).count();
; y9 L8 t2 q5 i4 J" i: x, B如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
. w8 t( V- S6 t& s$ m$ s/ A$ G
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
  n7 O2 E! ~5 Y& d& d  R

8 R8 i" Q, S( C# o. F2 E分组group()
1 f8 g* w& D" [8 A$ C假设test表只有以下一条数据
) P2 |% `# `+ I4 A! a! z
  1. { domain: "www.mongodb.org" " D5 d# {3 v$ V4 _8 Y3 r
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} - b! ^4 S) B; ]3 G0 C0 O4 ?" g; {) M
  3. , response_time: 0.05 6 z% l% |, y# C% `7 f
  4. , http_action: "GET /display/DOCS/Aggregation"
    # _7 O% W) q. r- ?! B9 B
  5. }
复制代码

" K4 T  d, p' }4 O! p5 Z& J使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
: D2 a$ T5 n1 B' z
  1. db.test.group(
    ! D9 y/ S& W4 ~& P( J# X
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} : E  F& s2 a; C' L- l4 y
  3. , key: {http_action: true}
    8 q6 ?9 H. F2 O. ], y
  4. , initial: {count: 0, total_time:0}
    9 k1 M+ j) o. F3 y$ K9 m
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } . N- v3 v' v0 D8 @( B
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } 5 Q( c- B; b; U: O6 y3 _7 K% k0 [
  7. } );
    % f4 ]& I0 a7 U6 k# @
  8. ) V! |- h/ M$ }2 J- _$ u8 c9 ~
  9. [
    / M, ?. t- O/ p# v& s: ?" Y
  10. {
    ' L% G/ V& I$ a& m: O- {
  11. "http_action" : "GET /display/DOCS/Aggregation", , p; `0 l. b5 p$ P
  12. "count" : 1,
    3 @. |9 y# `+ y9 S. e  o6 S
  13. "total_time" : 0.05, ' H. U% k6 F6 o
  14. "avg_time" : 0.05
    : h* {6 T) {  Q
  15. } 7 R* K: N2 `, {3 J, V2 ~8 y
  16. ]
复制代码
# K. s4 P2 `5 N9 E+ q3 ^0 T

8 l# V. z4 @0 _9 A8 e, C5 y: C, [, R/ q( u
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
    9 H( B  z7 F) u3 U) s
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
1 _' R4 j5 c* C9 ^) u% o
& y+ S5 f- q8 o! s3 q

3 M: y8 j) B* j+ |6 z$ a6 T
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    9 W6 m8 |) |* J6 `7 m( B- k
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
' K3 M& ?% }9 {% r) v9 Z
1 Y( }9 c+ y1 ?$ p! Y
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
+ A6 a4 n4 i. _! k4 r8 W1 G
9 ~2 d/ V4 F" A5 |% H7 |" N
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
  K: U" E% D1 j5 c; i2 v; ~

+ A) {$ d; v0 B- M! M, ?
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
* ^/ J6 N6 M  \/ P" h
( y% P( Q: k0 r* D# W  c
输出如:
  1.         , B/ A% E7 V( p0 W
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

7 N: s8 Q0 d7 d  T2 b2 |. V' o4 A
  H5 w( b; P9 u* V  i0 A, @4 L+ W' Q. e3 Q2 ]8 j' W
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    2 n  L8 Y' {3 p2 e% h
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; f9 U: b; l* S4 w/ `) _
  3.        xmlns:context="http://www.springframework.org/schema/context"
    * }1 c, q( }& j- B) o
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    * W' w7 V& ~& {* u0 Z1 T
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    ! V8 K7 a( f# w
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    * ^2 n; P. s4 i: b+ F! B% W) h4 I
  7.           http://www.springframework.org/schema/context
    $ f8 O6 R9 x  `. u* A5 V
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    9 Z, \7 Q( }6 \
  9.           http://www.springframework.org/schema/data/mongo  w/ r' h! y, D
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    8 N! h5 {9 m8 c. |" r
  11. 4 q0 Q. _+ L$ N8 M
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    " ^% I  B  e1 O( y; W
  13. ' a% V; P7 g! `. t1 q# a3 h! x
  14.     <!-- Default bean name is 'mongo' -->
    " X9 `0 D  G! G% v9 Y
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />2 i& y2 h! w* o
  16. $ p: R' [2 O" G8 v
  17.     <mongo:db-factory id="mongoDbFactory": ^! c6 T* b% A, Z8 d
  18.                   mongo-ref="mongo"
    - x0 n) _+ |; E& f% n! \" w
  19.                   dbname="mongotest" />- w, R: L  e9 |& |: Z
  20. $ d' Y# r3 M! z8 {! i
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    9 Y% l& y; y, Z
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    + }3 g" S; v$ `. t# f% Q% K1 n' c* Y
  23.     </bean>
    ' U( N# w7 f6 ~7 a# `: u) u  P: g
  24. </beans>
复制代码
7 B/ }" ~; J7 A0 ?. b) n

* ~; h) {8 X# \* D8 o8 k
maxmin的测试
  1. @Test  ~, F, E  Q  ^( H9 k, Y( t
  2.     public void testMaxAndMinAge() throws Exception {
      Y2 V4 q$ M4 w  }
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    . G2 S/ ]- G  z( S+ N6 F" J, n
  4.         Person result = mongoTemplate.findOne(q, Person.class);. }; j3 v3 Q. M
  5.         log.info(result);
    ( E9 w' W1 U; Y( U- A3 s4 z4 S
  6. 5 S: H# k% v8 r( g0 M4 J0 I1 n8 {
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ( k) E. v3 D# p* V* A- ~% T
  8.         result = mongoTemplate.findOne(q, Person.class);
    & T+ t! @- G! \( i  ^
  9.         log.info(result);9 x, x' j$ _4 P! p! A8 w2 l
  10.     }
复制代码
$ G! z/ d! ~; Q: o
. H* u- M" }% P
distinct的测试:
  1. @Test
    / A/ i4 C1 Z4 ~; u% o- ], a3 J  `% w
  2.     public void testDistinct() throws Exception {; K: h$ H9 r# Y* ?, t- I- C/ x
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");; o0 g7 V: F: J# Z: m/ q' s; c
  4.         for (Object o : result) {) a5 p8 I5 |, i; x
  5.             log.info(o);
    0 F7 h9 R5 K2 k8 w: g' ]; ^3 l
  6.         }
    ) X' b! L- i. |1 j3 L

  7. " b4 o% G, |$ R, s
  8.         log.info("==================================================================");
    ! Z; i  ~# |- R; u
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    * U/ l9 S+ M  `0 m/ Y
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());7 p. w% W+ ^5 K1 |
  11.         for (Object o : result) {
    & ?. X4 w9 D' v8 n! ]
  12.             log.info(o);
    ! B' I1 U( Z" W7 `; Q3 {7 P
  13.         }8 U# j, M7 E# D, |, \: t$ M

  14. ' N3 {' R" v8 e' h* [' a+ V
  15.         log.info("==================================================================");0 k2 c& k/ \1 p7 x9 G/ M0 ]
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
      B/ X3 Q  f4 [6 l6 G; N( q
  17.         for (Object o : result) {* g9 _- v8 `9 R7 k, N
  18.             log.info(o);
    7 g4 G8 g; V9 P0 _
  19.         }
    + Q/ d* R, a! D# p9 y8 _, L% b
  20.     }
复制代码
* ?; m; p6 b6 q8 {7 p# u( A9 H

" e* R; |  Q6 G8 e
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 2345671 i0 |+ E! P0 h7 z! ?
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    ( K  l1 g5 T. f: j2 W
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789# U, h0 o; \' l) b
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876543 B0 R" r& ^- c
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni) _0 D3 G! f' ?" a/ D
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    5 N, ^4 {/ d8 v- Z- K$ g
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    8 A+ r$ F  H2 P
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    , x4 A' e: W4 p9 x% l1 U
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    * M7 m1 f+ W# ~( E
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    9 L& [, T3 ]5 v
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567898 v2 t! ~6 E8 ~4 f* _$ w/ f7 Q
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    1 N# [) l0 S- U, _, w8 j  b
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================! n$ T! C1 }) ?
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa5 Z% {2 Y4 @8 ~( Q! y
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb) c% _" I5 S7 T  h
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    % U, l, w( x- q. |2 E+ [+ e/ y
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    + h- w( m, X, U0 D, J, ?- J+ H* M
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx3 c+ k5 L( q8 k& d
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    8 |1 g- C$ q5 j% e( G# v- z$ L( W& C
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    5 n5 [. ]: |8 ^
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    8 I; x' \, J  `5 G/ d
  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
复制代码
9 b0 z" N! E. K) O3 v& q

0 ^7 l4 N/ I. B2 ?9 |
这里我要特别说明一下, 当使用了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等信息。
& z6 j7 G# f, ^0 y2 i7 d; l5 J

" j9 C; C( p6 [
( D8 d4 B( V3 f2 e, U5 ^
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 11:46 , Processed in 0.065034 second(s), 23 queries .

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