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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:7 N  t. g. `: _8 p9 }% k

* N, q. v( M* ?. P  F$ F" o1 ) . 大于,小于,大于或等于,小于或等于8 I& F$ m9 k! v3 r' x, Q

( a- K1 \) d& D2 x$gt:大于+ A2 Q, Q: q  K
$lt:小于
% g' O, S9 z5 ?; _$gte:大于或等于
$ p, ]& V/ \' n/ o$lte:小于或等于
0 F9 u( b5 b* ^5 C- T! }9 d% Z9 ~8 g- Q0 `
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value9 U" D( \4 R; I/ s2 |: X, X8 ?
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value% O0 r3 c% e8 ?5 X+ g! g- p
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value  R' Y6 N/ ]: ?# w
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
8 v3 Y" C& H3 v  j
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    1 p! `5 g3 M$ Z/ \2 l  T
  2. db.things.find({j : {$gte: 4}});
复制代码

; c$ Q' d$ G- j( V& S( O2 ?5 ?. y& O
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

3 d8 [2 k& f3 ^3 C: _
( B& Z$ ~3 O1 t1 @
" z  `/ y' @2 r
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

7 C1 w4 w  S( s* i
3) in 和 not in ($in $nin)* ^, d+ j+ x5 N3 D" ~. x

: b$ L3 S/ V! Q' P8 m- @) @) P7 S语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

' p$ w1 K8 z! ?5 R0 I% R4 r
例子:
  1. db.things.find({j:{$in: [2,4,6]}});6 i5 c% |. y: V- G, S% A7 {
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
- X& V% y# y/ B8 u% @
0 D1 m- x( r( n8 I! H5 M
4) 取模运算$mod
( \  q+ n1 m9 l8 h' X& W* `/ b( B& `
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

* `& Z4 s$ \, b6 q/ K  D
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

. r8 i0 S. u# F. Y% h4 E1 {, v5 a. Z

( i) N5 e5 z, H+ R' S+ Q5)  $all
, l" {. F) i# V( \6 u  _5 D% t) Q# b3 X* [* ?: l
$all和$in类似,但是他需要匹配条件内所有的值:4 H9 N7 Q% p$ B- X: v! k0 n

; t0 J' G( f1 X, _: F, {如有一个对象:
# i! L% i! N+ E8 Q9 X' \, N
  1. { a: [ 1, 2, 3 ] }
复制代码
3 w+ e, Z  J3 G+ b  c' L
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
2 }# u% j3 G: d. k
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

: A2 v4 X2 ~( f' M: }( C# B" B
  f0 N& y$ M; K- L7 q3 s9 F
6)  $size
' h! h9 u5 r, T: L" w' `2 U* ?5 b! N3 W# n% Q) e
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
/ X9 m4 |- e( u+ C; O  ~
- B6 s9 w- J0 Z( H/ Z, Z0 k% J下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
% u; D4 Z9 @8 K; y( e: b
官网上说不能用来匹配一个范围内的元素,如果想找$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.
$ x; T- }/ }7 w* G" y2 F
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    * d# n( L0 Y" d5 Z7 M. u$ x
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
% K" W# }  y& _' i& f; ~4 {4 k
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    / z3 T2 M2 }% s# n
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

4 ^* Q3 ]- m/ N5 }" m" Z9 t! c
9)正则表达式
" I. k4 _+ ]& w8 @" S1 n! C
1 O% @1 k; L  dmongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
( L# u, E9 i8 c1 q5 f5 n- L) W) I
10)  查询数据内的值0 }/ y% U+ F+ u# v7 J" j. |$ d% {) T
& a. ?5 }/ J+ W/ G) Q& F" a
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
. {( c0 p# o1 M3 k
11) $elemMatch  t. W7 C8 ~( z* T
- O  ~/ _3 s- `9 _! Y
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 5 l2 C- [* C9 ]; i2 V' X# g
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  , q; i8 x% j9 p) Q+ @* o% }( f; {
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]: O0 o3 {8 C: l$ e: t
  4. }
复制代码
; j: j2 I6 J; c; i" ~0 B, G4 o
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
7 I( {& W/ `+ Y* s
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } * X  b/ y6 u4 z

) j* _& X1 n+ H12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
5 l0 O+ A6 x: @( `1 r; e" ?, r  H
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

: V" T) R1 g3 \! O
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
3 u2 D. D+ I) J7 N; H
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

- a, }  L$ q( p5 [5 _3 Q
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
. F5 ~2 A: s3 h) X
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

( |! y+ }2 a7 H1 d7 @
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );+ V# q- @9 E" ?+ ?! j5 F
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
; U0 \) w) {. f- ~0 L
mongodb还有很多函数可以用,如排序,统计等,请参考原文。8 o0 Q  E( o  p& @2 Y  C

" |" |# Y* }. O3 c1 Y2 `) \- lmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:5 U* z# {) I/ U" L+ H+ s$ {6 p
- K2 o3 ^9 o* X0 W: a# v( y
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions4 }: T7 P- T0 [: i% ^% G: Q% U  J

( b: U! a; c5 E. B$ G# g版本二:
% i) `& Y0 s+ e' r2 O0 e: r: L
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

- E( Q* A2 ?9 ^8 A
  1. use admin
复制代码

! \' F5 }: e7 n- |+ V
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

, I3 C( t/ y: _9 f' b4 H; s! ?3 F
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
$ B1 h. M9 E1 q+ D# R0 d) t% e
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

2 H, X! {  F3 ^7 p
         5. #删除用户
  1.           db.removeUser('name')
复制代码

& t0 {: }+ M  q4 M/ Q- e
         6. #查看所有用户
  1.           show users
复制代码

8 ?' L; O( e$ f  ~! d( i- L
         7. #查看所有数据库
  1.           show dbs
复制代码

! L# _& G; Q( m5 u9 P
         8. #查看所有的collection
  1.           show collections
复制代码

9 I/ Y3 r3 g( \( d3 J! P6 L
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
+ {& l' K* m6 k- b9 ]
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
0 G3 S7 r7 u+ e; U7 A' u, c6 I
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
6 m) H6 z$ p+ Z0 i! v
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

6 ]" _) N1 i3 S5 T
        13. #查看profiling
  1.           show profile
复制代码
* H; @( T# }3 U: M4 k
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

" p) v: V4 i0 k9 v
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
, x( }1 H. t0 y3 s
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
- s9 V7 q" m; A5 b& G7 e4 V) m
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
. `& l8 H1 u2 S# I7 z+ f1 e
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

+ V/ x' c- W3 g
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
3 ?* W/ B) P: M5 u' W+ j) r
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

5 ~& t, j0 y' ~3 w* l( A
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
4 G; D8 Z! V3 j- N1 }
   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()
+ N& [. I$ ~! s, o
6.  高级查询
条件操作符
8 R+ ^- V# W1 x3 b
  1. $gt : > 4 [( u# a  w& |
  2. $lt : < # I  z. h/ J& H! a- L2 Z
  3. $gte: >=
    5 r( q% `: B: |& A" s9 F
  4. $lte: <= : a& ?) X  }& `  z" u2 L( G( q
  5. $ne : !=、<> * j9 ^, p8 Y, ^  q% |5 h5 l6 r
  6. $in : in 5 I0 S7 }% j8 A5 R8 F* O" F# N
  7. $nin: not in ( H; y+ e  L! K' F1 v) Y
  8. $all: all # M# l- N6 G: h  x8 }
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
4 |, o3 I2 K4 d! X8 v1 ]* ^
& m6 J, L+ c4 B; O& W+ _
查询 name <> "bruce" and age >= 18 的数据
7 L% K7 E( {5 D9 k
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
% @- x) H& z6 l2 a7 g
+ F4 M; J5 Z: u6 \
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
9 S0 |* r' @: Q& }
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
' h7 J' z: @  D* ?3 x6 t
# w2 O( l( M( C
查询 age in (20,22,24,26) 的数据 * ~6 a8 [7 s/ \+ F* a
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
& O5 _% C7 N# [0 j, Q$ V9 A
" l; X4 w8 H8 d, `, X4 j
查询 age取模10等于0 的数据 ; l. S3 x% D4 {' c  c' l
  1. db.users.find('this.age % 10 == 0');
复制代码
9 c8 E* J8 A& x) E7 |' g! M& P) ^
或者
/ k, {4 h% v" a! M/ S+ ^6 H
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
% Z* z) A6 H# @" G

) Q# Y1 D5 K# j# \( M8 h匹配所有 0 ~. H, e: q. \3 o( X+ L
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% {2 |( e( q  S; P6 n& M5 o$ N! h/ ~
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
# I$ U9 `4 M! G$ I: \可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } ! A% A% p$ f/ W. W' l
$ {( k: J; [5 p, X: X
查询不匹配name=B*带头的记录
! g4 v# n4 d2 n( S
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

+ ~2 F( ~+ a1 j* A  D7 X& h0 w查询 age取模10不等于0 的数据
+ u$ q& ^& W' I+ {$ L* ?- T  V
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

- v0 p' Z. x$ `# ^6 g
9 p# |9 x  o. Q#返回部分字段
' p5 n$ b) j; x选择返回age和_id字段(_id字段总是会被返回) ! F  v2 p) j; {1 }& t
  1. db.users.find({}, {age:1}); ; H% \. D, e$ A
  2. db.users.find({}, {age:3});
    . ~# g5 {2 H+ j( F. ^
  3. db.users.find({}, {age:true}); . o6 v7 N: j4 |  ]
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

! V; }3 b- @' y3 d% d/ \, Z0为false, 非0为true 4 N# C' P2 J  L+ i) p  w
+ P1 N% T! f, x# Q0 V9 y
选择返回age、address和_id字段 * t  D! v* L* F2 R- H, O
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
4 D& c; w$ Q' {/ o5 i3 j4 j$ K

8 a$ Q. ^0 p6 n1 f1 W  H排除返回age、address和_id字段 & o8 n, u" U- F4 P5 @+ `# b
  1. db.users.find({}, {age:0, address:false});
    9 Y; r7 }0 L5 ?/ a+ D4 r
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
" @9 p( F& s8 P& n, U  V6 Z: I
& f- N- B8 n2 i5 Q" u
数组元素个数判断 ) H; f% {( x. l( n" |* @3 t9 s
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 6 O$ B* T. c* F! B
匹配db.users.find({favorite_number: {$size: 3}});
( k% c# z0 K, H0 M9 v不匹配db.users.find({favorite_number: {$size: 2}});
% k! _" U" _2 p* A; o
- O3 U! v- O) t5 j2 y. U) H( |$exists判断字段是否存在 ) f7 W/ C( H. K% {" J/ h, r
查询所有存在name字段的记录
, b5 F3 N* N3 p+ F- R6 E
  1. db.users.find({name: {$exists: true}});
复制代码
; J. ^0 t- q: ^" e5 {
查询所有不存在phone字段的记录
( E; M" T2 r6 L0 m1 g+ F
  1. db.users.find({phone: {$exists: false}});
复制代码
5 i9 l2 f) v: j) ]* z6 b/ d5 P
- k6 a4 C" y7 r$ \' {
$type判断字段类型
# ?6 ]6 o: \' a# R4 |. c& O7 V& x查询所有name字段是字符类型的
! N* G3 I% g3 F# w. d8 X1 @
  1. db.users.find({name: {$type: 2}}); 5 e5 y3 P9 }% W! O) @
复制代码

3 n: ^. K  ?9 e) C" T/ p# M0 M7 y查询所有age字段是整型的 1 |' k8 x. ^* W6 I. D/ H
  1. db.users.find({age: {$type: 16}}); + v9 B- y( |) z, l2 ]' S2 {( C+ O2 T
复制代码
* K. r# F- W8 K! O2 Z- i
对于字符字段,可以使用正则表达式
$ y7 Q3 K; f+ d, f1 N1 }9 S; o  L8 v  D查询以字母b或者B带头的所有记录 ; D0 I9 @  `: l7 E; l
  1. db.users.find({name: /^b.*/i});   W0 ~' p( V9 `
复制代码

; p3 o2 G1 \/ s& T8 F$elemMatch(1.3.1及以上版本)
& i" J# O# Y" e" ~, K6 x0 E为数组的字段中匹配其中某个元素 # c: U0 I4 w" m
5 C5 ]; _+ S; q' P
Javascript查询和$where查询 ) `7 L" L. q+ n+ Y, R. @! e, k! U
查询 age > 18 的记录,以下查询都一样 5 b5 i' t# H& V& X6 W1 S2 A6 `
  1. db.users.find({age: {$gt: 18}});
    2 s  a7 G8 k- |% w
  2. db.users.find({$where: "this.age > 18"}); / y) a( T6 I7 ?  O3 G7 `
  3. db.users.find("this.age > 18");
    ' z% X& P6 s, }: `2 c
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
0 \, k- X  r8 C5 v( ^
" I& ?! [. b8 w3 v  d# j- u
排序sort()
7 y* V) C5 j, g+ {3 Z以年龄升序asc
! ?0 k7 i7 x& {
  1. db.users.find().sort({age: 1});
    ! Q) b4 ~, Q5 h( q6 u9 g
复制代码
$ z! y1 b+ `- P# U2 b( f: c; r
以年龄降序desc
; G. U0 t/ i& V( @* k. B- J
  1. db.users.find().sort({age: -1}); $ J6 u+ X( w7 K! T
复制代码
5 {+ n6 b# K. W8 L
限制返回记录数量limit() 6 C1 B( a9 ~3 ?& |! `
返回5条记录
7 m9 Y6 @6 \1 \2 ]  G% O- ?* N  }( u+ B
  1. db.users.find().limit(5);
    ' L! c. H5 }- }
复制代码

. u5 T' b: |/ W; i返回3条记录并打印信息 $ a3 g: N5 C( |9 m1 w( C# d# h
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    & H2 P+ l2 a6 f4 r
复制代码
' I. u* _1 Z5 e. Q# t" k" m% P
结果
; [4 ]$ ~7 P* ]2 @8 Y/ m3 G
  1. my age is 18 ! j* `  t' ]$ t& s; \
  2. my age is 19 9 ^, \& d* L( `$ ^9 w) u  R) P
  3. my age is 20
复制代码
& I' e. M; ~' R/ j1 W' T9 A3 s
# ~) C$ I) x" B( R" V, q# |1 z
限制返回记录的开始点skip()
0 h- z# Y% S; [% M; e从第3条记录开始,返回5条记录(limit 3, 5) 0 a. O+ S* @+ [9 p9 }# p- H" h
  1. db.users.find().skip(3).limit(5); ( H+ G: U3 P% o3 b1 D
复制代码
1 F4 m) y0 e/ z& F3 P
查询记录条数count()
6 h" T: F4 @4 O: Tdb.users.find().count();
6 f! Z( f& Z: {9 Pdb.users.find({age:18}).count();
2 l9 A0 t2 R8 s  w以下返回的不是5,而是user表中所有的记录数量
4 ?4 |' y  p7 w) bdb.users.find().skip(10).limit(5).count();
1 C. b% u, J5 H3 [; Z& y如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
0 B; L! a/ |7 ]5 K, C% t
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
, D' H+ {, D$ e% t

2 P9 b# y5 _0 X/ x分组group() ) A2 |/ Z; M; d: i2 o
假设test表只有以下一条数据 * Z1 U: H: ~8 @# l% h* D$ @/ |
  1. { domain: "www.mongodb.org"
    * Y7 n- H6 o. j3 e- ~/ l
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} . I6 p; D* G2 [( W2 o# S- m7 ^
  3. , response_time: 0.05
    $ a5 G" J' I9 r5 T  A$ _
  4. , http_action: "GET /display/DOCS/Aggregation"
    0 H1 G" @3 Y3 x1 i$ t% N
  5. }
复制代码

" X1 p/ j+ K; ^使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
3 E, j& G. |" A/ B  y
  1. db.test.group(
    9 \+ U. J' o4 K% R" V! T
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} 7 T" s; h1 J, k4 v4 Q. H
  3. , key: {http_action: true} ' F! A8 h2 H2 ~% R$ @
  4. , initial: {count: 0, total_time:0} 1 P4 C& y) i5 J7 J2 D
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    : Q- [% N1 i" l' J0 p0 a
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ; }( Z/ N; p9 F$ H
  7. } );
    * e9 p! d& O  Q! ?& E7 s5 q

  8. ) g# J9 h  W5 T# N% E1 {) g! R9 a
  9. [
    2 s6 Z& Q, o4 P- i, w- W& N) z
  10. { $ _' O, X, ~3 U2 H# z+ b
  11. "http_action" : "GET /display/DOCS/Aggregation",
    1 G( q9 ?1 M# @( c" s
  12. "count" : 1, / k& Q* K  t' _9 A+ z% a
  13. "total_time" : 0.05, 5 }7 r- Q4 ?$ T0 s4 H
  14. "avg_time" : 0.05
    " o% L; N1 B6 P# ]" C" d" G6 R0 b8 |
  15. } * o' a8 u- u' M: v5 B
  16. ]
复制代码
9 |0 ~$ s4 r; V$ M0 V
1 ^* g" d& I+ |) h1 S! r: o

% |# u) a; m7 E) {. V0 f/ U9 ?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 和Min3 J/ S* @" Z2 S9 s1 o% c
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

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

; A" L( p) k) t, b* r
! w, L; |! K, ^
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
8 G6 z5 J3 E$ @0 V& W

; @: ?- z9 D& @! \2 x
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
  J. K, ^( v' r( o9 @
7 ~8 }0 z: B& |; D6 t
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

' g  E* @( r$ t. b- u0 s
0 M  J% s! s% I) H" q' N) h
输出如:
  1.         
    % U6 @* X! X8 t+ q
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

' t  P6 e: o& _8 e9 H& \9 H/ h  ]& _2 f3 R; E  t: G
3 w$ u- V6 u* M$ E/ u+ O. T
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    , a1 T* i4 v2 O1 _3 T8 I" A
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance": C/ ^5 r: W) I
  3.        xmlns:context="http://www.springframework.org/schema/context"
    ) \8 s2 m, @% G4 D! ^5 y
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo", K+ B" D. Y1 J' x
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    + m  z5 v( t/ |7 o' J4 ~
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd9 j# [* N# Y6 f' A; b
  7.           http://www.springframework.org/schema/context
    ; l& m+ f$ x; y( ^) q. M
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd% V2 d3 N1 F( L% j
  9.           http://www.springframework.org/schema/data/mongo3 O8 P) b0 g& b  C& U/ n
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">8 y; T2 f1 N1 |' d( ?

  11. ! ?! l  Y6 @  R, z, O) ~
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    ) m3 B( V1 y% d7 i
  13. 0 k7 l$ f6 T; U3 `: x
  14.     <!-- Default bean name is 'mongo' -->
    6 Y$ L! c7 `8 U+ f. E3 b
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    0 H% O  H4 E& `$ b: c6 L
  16. & g' `: w2 m7 `1 `9 H6 {& o  H2 G
  17.     <mongo:db-factory id="mongoDbFactory"/ M; G8 Y9 E2 a# v5 y) H" x1 m
  18.                   mongo-ref="mongo"
      X8 U+ i3 s# T
  19.                   dbname="mongotest" />
    7 D7 B' A- |# J9 {$ Y

  20. : ~+ {6 O+ R' u. \" T0 B3 T! F2 W
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    , T( \) }: M; L  G$ f
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>5 j4 o* T+ |3 ~1 D0 A' @+ O
  23.     </bean>
    3 K- c; U, s0 |" E9 R! q& r! B
  24. </beans>
复制代码

/ {7 ^/ T3 k4 i2 p1 e
$ w- z1 ?: R) l) {1 {1 K- U6 U
maxmin的测试
  1. @Test& ~+ Q3 m% V1 {. u
  2.     public void testMaxAndMinAge() throws Exception {
    - o' z9 C, K; R) d4 y
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);3 N2 n) |. ?$ t
  4.         Person result = mongoTemplate.findOne(q, Person.class);7 _9 o1 x, P7 S5 ~
  5.         log.info(result);
    5 k: e0 W0 c0 L! U/ f/ ~

  6. 9 _* V. C* E& \  I, q: \% M- C
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);+ {3 O/ C2 S# b3 J" X
  8.         result = mongoTemplate.findOne(q, Person.class);
    , b& ^+ b( M6 C% B/ i
  9.         log.info(result);
    * W/ j7 G! b+ l1 M0 ?+ q
  10.     }
复制代码

( ~2 d2 K% g# O: n& [* N8 g2 Y" N
) j. Z2 z5 N% N, n
distinct的测试:
  1. @Test1 ]" m) h/ W: b) W9 g
  2.     public void testDistinct() throws Exception {
    " P$ O7 V, |. e4 |* E/ k9 W- y7 e
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");4 {2 ^: u0 ^, o5 o/ s# S
  4.         for (Object o : result) {
      c! z9 g8 ^- W. i& ^3 p
  5.             log.info(o);- C( `0 R% |% c, _" C
  6.         }
    - k5 P  L  ?+ ^( a7 D' E! d8 Y
  7. 2 B  \; f% ^; s$ e% q# O
  8.         log.info("==================================================================");
    ) ]) t% d( A. {/ w" q
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));/ n8 }2 R' |/ _# `
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());# z* s& A+ s; S* v5 K8 n
  11.         for (Object o : result) {1 @: ?2 r  f+ c1 r, S& M+ |) y% [
  12.             log.info(o);; ~+ R. d" l, B& f2 g, K! ?
  13.         }
    . a3 G  ^1 \" Q- c

  14. # U: r0 \' ^9 C! v: d
  15.         log.info("==================================================================");
    & }/ S# j$ p4 ?* @
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    0 t- V* Z9 N" g+ y  t  a; I. B
  17.         for (Object o : result) {
    4 }7 x9 ]% M# @1 b4 s8 Q: [
  18.             log.info(o);7 D, D/ b) {; y
  19.         }
    , ~) x; a5 s+ V" b8 I: _
  20.     }
复制代码
1 r8 `( Y& ^, p4 b

& I0 I/ S- L" X
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    1 O. [; C5 G9 I- o! i" o
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678& x: C3 X% i% _& Y% m
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789( k5 E5 i) D* L9 i* w( E& W
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    & w) n9 j3 @+ ^8 l6 ^
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    : `  V3 S6 J+ M9 V% Z- H
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    8 g% y( h$ I& ~. D, _  m1 Z) H3 q5 D- s
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    9 H, e4 q6 I. P& J0 {
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    & X  ~8 h/ P! }& i' N
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    5 F9 S: R1 W( V8 b, B
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    9 c# Y4 w. }5 E; o* O
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789+ Z9 A( V4 W, w- z* k. Y
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    , i0 V) X3 Q; w, {
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================+ C: i2 w* D' E6 g/ C$ ]( v
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa& X1 `: `: R- I$ ~; a1 t( h& e
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb1 [$ I+ I' U3 ]  _( r6 c3 [+ F
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc, M, w. V& {( C' r: G
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    % m5 n5 |1 a! D% _: w/ u7 s
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx/ t' N, {& y$ _
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    ) F$ T0 Z3 ^6 T6 k2 n
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    + i. o: A7 a+ l+ ~4 ~
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr  A. i' Y% k/ P- @6 l. S
  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 ~  S" v9 _% C) m* h7 w3 m: Z
2 P1 ~0 d( d& N8 v2 j4 R6 k& V9 K
这里我要特别说明一下, 当使用了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. \$ \  h% j. v; i! D
3 g* l0 f8 |8 ?# ^5 j3 c/ G
4 s/ ~- ]" v6 E& S6 P
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 20:58 , Processed in 0.131426 second(s), 22 queries .

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