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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:4 v  o/ Y! |1 V! r; }: p; E

% r" q7 l+ @& l1 ) . 大于,小于,大于或等于,小于或等于
* B7 f% J1 U% p2 I0 c0 [+ J% p, ]& }
1 |0 |2 L( U  l2 b( w' Z$gt:大于
4 r+ D( o6 w. f$ V$lt:小于
7 z0 L# B3 P. K% m  }( D$gte:大于或等于
# W+ D2 z' ~/ c$lte:小于或等于
; Q% j( e" F, y7 d  u
2 o9 Q% ]& w. L; \) }/ h9 `例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    % U; |! |5 [7 Y& U7 J
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    / O7 [" L3 X7 }. H7 F: i5 g$ |
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    ; n1 x4 d7 {" Z/ h) X
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
5 q6 s9 m: C6 r( b; K% Z: x  g
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});& g0 v2 S, F  z1 a& ~  t: C; Y
  2. db.things.find({j : {$gte: 4}});
复制代码

8 r' T6 B* Q' {8 t' [) }* U& w
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
4 {& P, R' }. J  ?' c
1 Z5 h0 x9 d5 H3 |; z

9 n' c3 C: o/ u
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
, U, e! J* C3 ]7 f$ J
3) in 和 not in ($in $nin)
' b: E3 {5 ?1 V0 G4 _3 x
+ _2 `% {, e6 L; ^% M  B% x- S1 D  v# B语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
8 r* b5 ^! m- C+ g; N* Z, ]
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    % f3 q' L6 d- i7 t( ?2 o5 w$ i1 F3 K9 z
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
  Y6 }3 h& u  ]* D6 d7 h# N

& e& m8 f' N4 F1 ]4 A3 B4) 取模运算$mod
. q+ \' D0 c! y% p' a
% S0 S3 o; |6 S5 @8 x( B如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
  {2 x) d6 s# a4 r$ b
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
- }; H/ ]) s) ?# p3 T
' V, d, D% R+ f  R
5)  $all7 F2 X) D5 o- V) e, V  F
7 y9 ?: ?) ~( d" ]# n
$all和$in类似,但是他需要匹配条件内所有的值:. w, i5 }4 h+ J, z% n" t$ C

: ~3 o: l: m( n) W3 ?( e如有一个对象:
6 O, R7 D  B) T1 T
  1. { a: [ 1, 2, 3 ] }
复制代码
8 d0 v! b. D- [1 v0 y* D; \. z
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

) j3 o' B/ x' }
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

: G6 w4 z0 H* j* t( T( R% r

/ Y, |; Q: J$ b( D7 _" c6)  $size
* r  ?; ~' Z7 z8 S: k/ g
9 M$ [7 B- b% z+ T$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
  \2 E! h; G% n* O, U3 j: x+ L4 m: d( U
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
/ b% V& G7 X' X1 W5 p
官网上说不能用来匹配一个范围内的元素,如果想找$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.

, l! X. E, g- q/ a
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回6 o7 o& z7 X/ l7 n- _- h. ?
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

4 m3 O6 d1 H% C0 J# s$ l7 l& C- m: T
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string  T2 k; E7 F6 E
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

6 T9 {3 ]: I+ w% i
9)正则表达式
+ P4 ?; f" k1 d6 D7 `
' t' i6 u. n0 {9 p" @" ^- Hmongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
* \3 V) Y: V* S0 g' }
10)  查询数据内的值' |! w3 T6 o  @2 p9 N) x
) p) g  U' ]( g  q8 ^6 Z/ V: P+ f
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
5 t- N& A  d& f9 b! r
11) $elemMatch# x! u; t$ H0 o: M! w! i: W

3 _& m* R3 D0 ], y0 V' D6 A如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) " l0 d: |3 o# w6 Y6 }
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  3 ?; h4 ^0 ?( I% v% t, I
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    ! l# ~2 D, W# n. q& u. f+ W
  4. }
复制代码
! S2 O/ ?! r: I% P2 b
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
7 l2 I! N/ n- `- p* }$ E/ k
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
$ Z+ D/ J/ ]% c! ?) h( g' w" X! ?/ z
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
7 O4 X. s6 J, w$ J( R( `7 N( i
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

* L: J! l( Y8 _# }0 M7 B6 O
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

( R  V- Q& U$ A0 n9 R" i% [
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
6 `; F/ Z( n8 p
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
" l% D  l; W4 E' b$ X3 X
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
& ^0 j7 j, s3 e( o* d8 H3 W& b9 K
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );+ Q( l! f$ q9 o/ t9 M7 u% F
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
, @- y! s  ]- v0 t4 T+ Y. [  b
mongodb还有很多函数可以用,如排序,统计等,请参考原文。9 }1 ]) J, @; z# t/ h1 }: p

" q8 t: a6 n( O# Vmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
. g" s3 f" M7 q9 H& Z8 N) g8 Z9 f9 d5 R9 g1 w& a+ l9 r
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
% F- a0 ^) i+ w3 U
6 F# m6 n1 ?2 Y% T版本二:* Z+ M) Z3 H6 ~5 W4 q( S% m
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

! o. z" u% Y& F- Q& i$ p+ B
  1. use admin
复制代码

) l  T1 e5 o) @* b* C
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

1 n% G4 u: `. J3 m& v0 s* n
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

9 [. @- J. @5 j0 v4 h$ [6 G: A
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
' U, b$ K: ^6 F% v$ ?0 D
         5. #删除用户
  1.           db.removeUser('name')
复制代码
1 H, ~: W4 o# A9 \9 o( f
         6. #查看所有用户
  1.           show users
复制代码

7 D2 O- Q, f3 R; g4 D8 r; ]# @, m8 I% G
         7. #查看所有数据库
  1.           show dbs
复制代码
, t$ o3 H  O: }* v3 T
         8. #查看所有的collection
  1.           show collections
复制代码

8 x5 I6 H1 h- a" v* E4 L
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

" v1 w& E& _6 s/ Y9 {! A- Z
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

! \$ X5 [% ?/ W5 A- O" q! L
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
+ d% _+ |4 T7 {- M
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
& B! E0 ?' x) ^8 S; N( I
        13. #查看profiling
  1.           show profile
复制代码

$ W9 ~% n# Q6 P( i5 U8 d
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
! s9 A; e9 b, E( i; n) O
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

+ I. @; \* i( e5 ^7 s; j( p
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
, R; {# j5 n0 P$ J7 Q/ q& |8 R
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
- {9 s7 L8 `9 j  k' o6 N7 N/ P6 S. Q
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

+ M. o! S, f" X
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
8 H" X3 L+ s6 B3 _0 O) P
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
% y1 m  F6 u3 i; U# O/ x& c
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
4 g9 i& d$ e- N/ ~4 U
   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()
4 m0 k5 A7 I2 j) O  ?$ j# E4 F2 U
6.  高级查询
条件操作符 3 H. y# Y- P5 Q
  1. $gt : > ! j8 ~* I  Q7 O1 j
  2. $lt : < % u( [! x# Y# W; z
  3. $gte: >= " |( F# x9 i! b' [) N
  4. $lte: <=
    ! i( ^; Z+ S% ~2 ]+ ]5 S+ n5 Y
  5. $ne : !=、<>
    * y# j0 X4 F# F8 D
  6. $in : in * ?) v8 `' \# k& |# G/ B  t2 w2 Z
  7. $nin: not in 4 V+ T% u4 c. P$ G
  8. $all: all # X7 ?: N* |3 F* Q
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
# u, O% G1 r2 _) J

6 W5 j- L8 ?( I) g" t6 V1 D查询 name <> "bruce" and age >= 18 的数据
, G# k9 g- j' z5 g7 F( v; K
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
) T3 I, T6 M$ s. [) e7 i( c" \9 h
4 o/ K3 @; K+ O& J8 i+ P: F
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
* `7 y( N: }$ a/ d
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

  S& z. I% z% T* I4 J4 k7 a1 J' k9 J+ S1 |" r! v' A
查询 age in (20,22,24,26) 的数据 1 _/ H' N' V% s
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
& C: K# s0 X3 j6 c$ h

: t3 V5 W& a9 G$ |2 X6 p$ ?  o查询 age取模10等于0 的数据
) ?% x2 P7 w6 O" F
  1. db.users.find('this.age % 10 == 0');
复制代码

$ K3 D" B7 m/ Y; \4 S或者
* U8 A1 Q9 G/ R% b$ k3 g& \& y! F+ t
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

! \) Q% `6 O! S1 c9 H: A* w$ h3 o/ @! o0 c! o+ v: D
匹配所有 ! t* a) r" {: F* F8 b
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
" Z! u% j6 b- l4 I& {( p
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } ( e- U9 p, g1 @2 c
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } ; i- S) \0 p5 {& x. j

  ^9 h) U3 Y' O6 ~查询不匹配name=B*带头的记录 ; f4 }) Q: r' [6 W9 ]
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
# u4 X0 \/ P5 W! @  [( K; _
查询 age取模10不等于0 的数据 ' y' H& V/ z1 I7 \, I9 o4 G2 p
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
6 h' ?9 f. d- Q1 p% Z" v

! \, E: u# L% {7 o#返回部分字段 ) ^8 I' ?0 h* h1 J3 ?
选择返回age和_id字段(_id字段总是会被返回) 2 U: O) [1 t5 {- T/ o
  1. db.users.find({}, {age:1});
    & @3 @! r# m7 x8 [! u
  2. db.users.find({}, {age:3}); 9 W0 @6 i5 r: [2 L& T% v7 {
  3. db.users.find({}, {age:true}); 7 a+ T. b& {0 L% I4 R" t7 C5 Y
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

& ]" D: i6 b. [/ ^0 H8 x! v& V7 o0为false, 非0为true ! f& g- Y  _* c" U( e+ F; ?8 t) h+ P

0 C5 b  C: ~4 }: i5 B9 ]选择返回age、address和_id字段
, C4 @" E% y4 h' q+ ]) h" N% J
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
/ j* P# F* Q7 W6 q) i2 @

; F+ y! {/ q- H9 ?8 x排除返回age、address和_id字段 # m4 l7 p5 }8 r9 k3 |0 M4 ]
  1. db.users.find({}, {age:0, address:false});
    ! K; v) T* t( X0 g9 Q0 q. c- X
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

, w( p& \) [$ u# u- s2 [, s1 C$ n: p* w6 H+ _$ \" n. h6 d5 q
数组元素个数判断
6 E7 F4 i2 Z1 P/ @' `8 G  O+ T对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
8 \( d2 @" C8 W( I  ]匹配db.users.find({favorite_number: {$size: 3}}); # q& T% \' i" ^3 }
不匹配db.users.find({favorite_number: {$size: 2}});
6 Q9 L, d/ }5 P/ [5 r% Y5 C/ r* U& n
$exists判断字段是否存在
2 U: p$ j  P' ~3 Z- Q查询所有存在name字段的记录
" D* g' P+ b% \4 e* t- R: z7 n
  1. db.users.find({name: {$exists: true}});
复制代码
3 Z4 t! z7 j: P( ^. O% l1 T% n
查询所有不存在phone字段的记录
# b6 q) `5 j. |5 ^. m4 F# i
  1. db.users.find({phone: {$exists: false}});
复制代码

$ J. q6 t) W2 ?+ g& G( o8 m4 S0 r4 u5 C
$type判断字段类型 / Y+ ~* U" Y. F. }6 M$ G% B2 T
查询所有name字段是字符类型的 9 k* f5 l. h7 `: f' ]
  1. db.users.find({name: {$type: 2}}); 7 p3 `7 s! I& S9 p- a/ y
复制代码
' z3 _# m! d3 N0 E  }9 \) Z
查询所有age字段是整型的
( C% t& p, ]$ G/ y
  1. db.users.find({age: {$type: 16}});
    6 [* b0 ^5 _! @3 Z4 h
复制代码

) P% \7 ?, |- B" C4 L9 ?8 F对于字符字段,可以使用正则表达式
* w7 t4 H/ \/ N$ O9 @) b查询以字母b或者B带头的所有记录
/ x% t4 w- {4 s  K; M% |
  1. db.users.find({name: /^b.*/i});
    ( n' V' [3 L) C* i
复制代码

* k. n; U( R/ W& l* d: t3 r( w$elemMatch(1.3.1及以上版本)
  }* I8 O: ?3 w& o为数组的字段中匹配其中某个元素
  [8 ?, c( u; v' o% E4 C4 P% W# i' I% O9 y7 t# f6 Z) J
Javascript查询和$where查询
# T8 i# V0 m* t# v查询 age > 18 的记录,以下查询都一样
0 m6 c: u  h% S: X8 ~6 ~3 X: @
  1. db.users.find({age: {$gt: 18}});
    ! n; E! ~! U( @- k5 N4 l9 c, n, m
  2. db.users.find({$where: "this.age > 18"}); 3 n4 o. V' i8 D% E9 x% D: c* H! H
  3. db.users.find("this.age > 18");
      `: \6 D! n( K; n* J: v
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

* ]6 J, x$ e$ D) l
! q9 P8 D( Y7 C) g5 U排序sort()
  D. q( T- ~% E以年龄升序asc
6 m* K- L2 P! G, A4 C- }4 g' P
  1. db.users.find().sort({age: 1});   t% H* V7 O+ Z( k3 i. F  \
复制代码
# W/ r7 E0 a) Z& ?0 ^/ z. M$ ^, I
以年龄降序desc
* ]. n6 J; y. B$ W9 n' x
  1. db.users.find().sort({age: -1}); * L* X5 L% F5 T' W( h4 I5 `* @
复制代码

+ [7 u9 i; g+ u. P9 L+ |限制返回记录数量limit() : N/ o7 \' \* L1 f0 X! |' K
返回5条记录
( X" Z3 a  X( A  Q$ _, h. n
  1. db.users.find().limit(5); + G$ _+ w. H' V4 T2 Q0 k# A* Q" Q
复制代码
" R! P0 m* W- u8 q
返回3条记录并打印信息
4 X6 x2 j7 H! \  G
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); ( d! f  Q# u% a5 |  A" C# |
复制代码

' }6 H7 w9 c( e- X  D& c$ ~9 N结果
7 I7 k, |2 }# w) c! v; x
  1. my age is 18 4 a/ M5 G* U" E2 X( a. P
  2. my age is 19
    ) J+ q+ F# J( y1 H+ _9 N/ _9 R& o+ n
  3. my age is 20
复制代码

7 V+ W( x% u* V# l2 T4 ]1 Z5 U! K" k; N0 T
限制返回记录的开始点skip() 6 r1 y/ P% P0 p
从第3条记录开始,返回5条记录(limit 3, 5)
7 l3 }  e0 Q# z1 a( d7 o7 v
  1. db.users.find().skip(3).limit(5);
    - o! U- q$ a9 N+ x6 m$ Y
复制代码

& W9 o8 c, V) u) s1 i4 g6 r0 W查询记录条数count() 4 H- l! t; C9 j; P
db.users.find().count();
: R4 u0 @' d5 vdb.users.find({age:18}).count(); & a3 b2 t; w0 O* v2 b. v
以下返回的不是5,而是user表中所有的记录数量 % f; ~# E0 ^" m# @  a$ a7 F
db.users.find().skip(10).limit(5).count();
* R& G+ F  g+ _  b如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
+ [4 _  w4 r* b1 M/ s
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

( y4 k2 w$ q5 Z) d4 r; O* {8 z+ h' F* v
分组group() ) i& }) {2 w( p7 [
假设test表只有以下一条数据
+ r' B4 r0 P- [0 z4 \) l
  1. { domain: "www.mongodb.org"
    ( Q* a6 f: f9 |
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ; W6 ^1 t- l% t; {. S1 y
  3. , response_time: 0.05
    6 O$ e9 v) R! f; c5 f$ L7 o
  4. , http_action: "GET /display/DOCS/Aggregation"
    6 a: {0 j, u* E2 h: v, B
  5. }
复制代码

: y& G. Y7 N! `- O$ P5 A使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
  {  E7 N$ K' F7 x( c- E! k
  1. db.test.group( 3 C9 b8 n* }" G" o/ B' f! k+ O
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    3 F3 n1 i+ W5 j8 z0 ], U
  3. , key: {http_action: true}
    ( @2 H8 p' I. X- Z: K# p
  4. , initial: {count: 0, total_time:0} 5 n* G7 v9 B! U+ y% W' c7 z
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    ; i! \: y8 \+ ?" c) L) L' b9 u
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ( K* I* F1 [* n! U3 V
  7. } );
    / p  o- j7 L* d# o5 j6 Q; k

  8. ! O5 @/ [5 ]( T  I
  9. [
    * N& k  Z1 z* A4 J5 R$ f  ]; t
  10. { 9 X, i! V3 x: u! I( {2 }
  11. "http_action" : "GET /display/DOCS/Aggregation", # L+ X! I. A2 {8 y/ W0 _
  12. "count" : 1, 6 _9 }- b5 N/ |4 G  S
  13. "total_time" : 0.05, & M& S# X+ h' l. s
  14. "avg_time" : 0.05
    . V" K9 J! n& X6 d" \0 D) }: B# S) v  `' Z
  15. }
    7 p: f7 |6 w8 P4 j7 Q; e$ o! F
  16. ]
复制代码
: L+ \4 ?( r' G0 i% r, t

. |& V; y- I- B1 H! Z! _7 A
5 o% Q  m: Z3 x1 l1 l# g* [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* Q) L6 }7 t: \; ~& W/ v
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
) k% ~7 u! A' l
* {! z0 B" m* g5 f" y9 }

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

( \+ U) q/ \8 F/ g, y3 B+ I6 \
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
' R( r4 Q4 w- Y8 {% }+ C
! Q) M7 F  N7 Y7 }2 Q$ u
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

% v4 w2 |8 i+ y" r+ s
: G) Z+ A% D8 J- u. q, m# T% E
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
# b; o' ?6 T3 C( [9 C/ A
8 p4 R7 Q# S* h. ?5 z  ^: p5 M
输出如:
  1.         
    3 Q; G8 }) K/ Z% X" o7 J1 V9 }0 t7 U
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
/ q2 P% o+ E+ ~# c7 ^6 R

! W7 S% \, [6 M2 T1 t* W& n
' ?# u( E1 c  I3 G
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    6 d& A. Z, E2 H
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3 Z& T% g2 O- X
  3.        xmlns:context="http://www.springframework.org/schema/context"; [! a" |! p' K' k% O- v
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    * m& l: E& ~$ J' h. J/ ?
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    0 I" Y0 ]/ R$ ^3 q
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    4 Q7 R& c6 `) W; v
  7.           http://www.springframework.org/schema/context( s' Y; h* ~8 d* `/ O" @* ~
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd& |% P! S9 Z& ?! I# A
  9.           http://www.springframework.org/schema/data/mongo- [7 c4 x- l# w1 i
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">) p, \$ W% X- P# M$ L

  11. / }* V3 o$ m9 o# O
  12.     <context:property-placeholder location="classpath:mongo.properties" />0 Q" o7 \! G: ~/ C- {2 n4 V: v
  13. # E1 a; P6 \! k$ y
  14.     <!-- Default bean name is 'mongo' -->
    + Q. S* X: e$ o: y. C; m
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    1 E1 v; C9 i# A; P. M
  16. + J2 R+ P! \8 L8 T( C2 g: e
  17.     <mongo:db-factory id="mongoDbFactory"
    1 N, I, \0 U! R
  18.                   mongo-ref="mongo"- _* z2 h  t5 I& }& [
  19.                   dbname="mongotest" />: `$ s/ v; H- d9 u6 `1 O5 t
  20. 3 I6 ~; S0 O2 |3 B4 o/ m
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">- y! [' C2 I9 z0 h3 u9 _* Z1 H
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    * S6 P% i% Z- d7 h4 w
  23.     </bean>
    * D$ h% I6 P4 T2 b0 |
  24. </beans>
复制代码

! c- {2 R) a: e+ {" e& T. k0 U

! o  `$ U8 h) c' A. a7 [
maxmin的测试
  1. @Test
    ) y+ @( ]; k7 y" J3 Y+ `8 j
  2.     public void testMaxAndMinAge() throws Exception {
    2 p/ l) c! Q8 p7 l. T$ r0 ?9 H: v
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    9 T; A  C+ [" Y+ w' ~1 l4 Z
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    3 Y6 u& v7 n9 P" ]
  5.         log.info(result);
      J  O1 b% p0 `+ t  Z4 C

  6.   D% X( ?2 U* l7 H5 R: r
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    % f2 k. e9 u, I! R% |, X) ^% ?
  8.         result = mongoTemplate.findOne(q, Person.class);
    7 A- }5 B; f4 q* j' D+ {! F
  9.         log.info(result);, U8 o1 T( ~$ h5 [* }
  10.     }
复制代码

( y5 A4 q% p$ {+ ^! ^
3 u+ G% O0 s6 h  _# ^; q
distinct的测试:
  1. @Test
    ; g* i. R; j) J& g1 @
  2.     public void testDistinct() throws Exception {
    $ ~) \  \' A- [8 [7 n1 X% O% ~
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    : B7 k1 M6 ~) o. g/ k& \0 ^) z
  4.         for (Object o : result) {
    8 E+ A; c1 e9 c
  5.             log.info(o);  r% s0 X+ t8 A" d9 H' b% J
  6.         }+ q4 r# n. a2 z8 l
  7. 3 m, \3 Q" s( x- T
  8.         log.info("==================================================================");
    8 l% Y7 Q: Y7 Z
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));! l) ]( T) _/ ^' {/ o0 E
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());$ A* ^9 p9 \6 `& g! j
  11.         for (Object o : result) {4 {' x1 a, e( l4 r" S) A7 A+ T
  12.             log.info(o);0 p- t: L! T3 l( Q. R
  13.         }" [- R8 `# J7 h9 o

  14. 5 y" K2 v+ \# \$ d+ `# F
  15.         log.info("==================================================================");
    . [; T! k- Q7 x. P* {  @( w
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    3 ~% p. S$ o" F+ k+ I2 V& s8 \6 ~, h1 m
  17.         for (Object o : result) {
    $ {; Q$ Z/ x) J2 n) m2 f& X4 d
  18.             log.info(o);& `1 y  [; R; L- |
  19.         }
    , G0 `. [2 E: A% K( O: @
  20.     }
复制代码
/ i/ @) Z$ Y4 U/ Y1 y" D$ Y3 {
  f2 l( Y7 [4 _: Q# I
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 2345673 r1 U5 _. J4 v/ L! O" P
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678: u5 c3 W' f' n  U4 C2 `4 o
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567896 h% V2 `/ K: H* [" T2 N
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654( D! h% ^6 a3 D( z
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    7 ]+ b4 }+ g, {7 r: t
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    5 `) K% U# e/ Y1 G7 g+ {
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 1234565 n* M; C- s' N! K+ a
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    4 E! c7 i0 b8 @
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567& ]% T+ Q+ ^# m. s$ D7 \$ `: R7 V& |
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    ' ?" [5 K: w! e# k+ D' u
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567891 ]) G# m( R7 y; A" D% T6 C
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    0 N; ^* J' j  D3 t4 e4 t% o9 m
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================0 v  @; J' Z8 U8 Q$ W) I
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa# y6 ?6 X1 Y7 G) a  d, ]1 v
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    ; T; s& N/ u) @4 U' o$ `1 ^6 `" Q
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    : A$ }0 O3 W1 G: Y3 D: ^1 n
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www+ {' O$ f/ j7 G
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    / n) Z8 Z' z  t$ I* t. `7 r3 ?
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    6 k$ r  |( P5 ~
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz: b" H# d* K' n2 V
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    6 W6 c$ u) ?7 F' W. J
  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 J5 Y4 y1 `4 c8 R0 Q7 V, w8 Y) I( g; j0 n% Z; ^' R9 W7 J
这里我要特别说明一下, 当使用了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等信息。

3 ?' u& M- X( _0 g4 p0 V2 _6 d# T, g$ D% M/ |: V

8 f& ^/ F" @* A2 b4 C' K
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-9-17 03:53 , Processed in 0.129586 second(s), 25 queries .

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