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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:: I. A  Y/ G5 r, j- i: P, `/ S

/ G3 y6 j& g. ^5 }. h1 ) . 大于,小于,大于或等于,小于或等于
* ?2 f: u1 [" B8 Y! Z" A
' ^( s/ D, D$ k) m" x$gt:大于
( Y: ?+ O5 X+ e1 u( }- }, Z$lt:小于& p7 ?- G  ?, i+ c; r  R
$gte:大于或等于" \6 I$ A* i- j# k3 e" `/ p& d/ i
$lte:小于或等于) ]1 i2 L' ~8 a

0 A$ M/ g: Y/ @, c' Z: ^例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    ' c% V( V+ F0 \( |% R5 u& q
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value  M9 g' o+ q  J1 f' `1 y
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value) m, o# g* V- u& h4 M$ W
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

/ W/ u' Y. Z) Y" v1 k& ]1 n! i
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});" p# W0 s% }7 q: u. Q2 `$ ?" p' X
  2. db.things.find({j : {$gte: 4}});
复制代码

/ ?+ k9 Y+ d2 V, Q
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

" }+ V8 z+ L8 A: r  r. ]1 a" r1 i! T5 `- ?  D8 [

8 }4 R$ Q2 @- S& b6 S( l1 [
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
1 P+ q; o" S! b) K! u9 k& q# _
3) in 和 not in ($in $nin)5 y- k% g" Z7 J9 q% f3 i, [
. U5 f( R# ~; W' g1 d0 a5 m
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

, f  Q$ r3 Z3 @/ w- d& C+ q. N, `
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    + h1 W  Y* w8 F6 x
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

+ A3 _+ O9 H# i! m/ b  n3 h$ m
2 f8 t1 P( x3 s8 R. M& Y+ o
4) 取模运算$mod3 Y7 y5 z0 ]4 m2 w. a" g4 r0 |% K  [

2 t' ~. d: _* Q如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

8 p! P6 k+ ?4 H7 c# K
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

' }9 V3 ^9 S$ R

8 _! ~# F- c0 V7 }7 ~) F8 A- Q5)  $all
' l/ d5 |2 ~% _! S) ^
6 p) ~4 c7 C4 w" y' e0 D$all和$in类似,但是他需要匹配条件内所有的值:
7 t2 \2 z$ o$ F& V9 \8 C1 O) f, t5 u* ~9 k. k8 z* f0 |
如有一个对象:
/ I( X5 d- T! k' _
  1. { a: [ 1, 2, 3 ] }
复制代码

& t2 x) r) F% V* ?
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

3 b# I* |- i; w& f8 V& L  |
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

6 @- c, U  n& {* g! q" P
  u3 b9 K- Q  R; C! Q
6)  $size' P1 p8 L! t& i- f' A
; E* n. Y) f2 N0 F$ S8 M+ E
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:5 y( ?( V; d8 n1 l' I3 B, j

5 S" B; ]" q7 j: V# E: P下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
' Q2 o- y3 n0 P8 e4 ~' T
官网上说不能用来匹配一个范围内的元素,如果想找$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.

# @7 W/ p7 L' ^; T2 q
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    ( R% R. n! e8 V5 O6 x( N7 t
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
, @2 z; ]/ A+ `, U4 E* m( G  w
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    + j/ W3 l  T+ Z9 H! c
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
& L* T, f3 D8 J# B' u4 a
9)正则表达式
& W. ?9 _& Q1 k" \, G1 U: Y1 i9 L& ^) e; U( s+ S
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

9 F# D7 i5 K( |- X; w
10)  查询数据内的值$ D" {1 c, a! U, w4 I" h& X5 y0 D& y
0 G3 Y: ]+ H) r1 j$ K; o3 v, j& n
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
1 S# n3 i8 I& k/ ]4 Z
11) $elemMatch  D1 N# n' _2 K* U* w6 \- o# ~+ J

- |6 Y& m/ g& c, N( F如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    $ I1 o+ J+ n& |0 i
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    - a0 h8 E1 v2 P4 z& {# W
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    ; X/ n  g) a/ Y( V
  4. }
复制代码
. C- a1 K% ]* y- w% A$ D( b
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )6 s: [9 v4 q6 m
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
+ g( U+ b# ~/ k/ T  n4 V; \  E, }  Z0 Z5 q; D/ U
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
0 U# G( q$ K; W3 T7 }+ F0 c
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

7 A; j0 D: e8 O2 l; Z
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

; @+ T6 J! |# V$ T# }  H1 A
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
1 q& {/ P7 y5 l) a0 v
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

# r2 }2 W* N( |! g0 ^1 O3 s
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
- D" Z( r+ z4 V# N  D0 b* ^% v
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );: @" \% M: X2 C& o
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

# u. K/ o  ~3 d
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
* M- s  G  h7 F9 `' g
' w& w8 G$ K# E) m; ~4 ~mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
) L9 }3 A0 {5 Q% Q  \1 Q0 Y' |1 d2 }/ o7 F/ g
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
/ I$ |' u: U, e. A) l
1 g0 p( C& ]: m; T+ T3 \版本二:7 h% x) }( D& s1 v2 r: L* b5 l
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
# `# G0 ?* h5 }$ m# `
  1. use admin
复制代码
5 K+ E% u" q) k2 _' H8 W) I
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

' B5 f! c9 {- f" j8 ?6 A
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

( u7 V& R. n% U* t8 D: }$ t
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
1 W% b5 A9 F0 U. \' p+ q9 I
         5. #删除用户
  1.           db.removeUser('name')
复制代码
- N' A, b, p7 e6 |8 u2 y
         6. #查看所有用户
  1.           show users
复制代码

& ~" y, f7 t; a% a# \0 p
         7. #查看所有数据库
  1.           show dbs
复制代码
; H$ y! y# r1 \+ y9 S# i
         8. #查看所有的collection
  1.           show collections
复制代码
  A1 u1 Z- A4 @
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
$ o6 c4 V& J) x2 ^
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

0 y9 Y3 e. m1 b9 A' J! h
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
7 _: n% W+ T3 `1 ?: j' x' c$ G
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

$ Q; v3 r' d3 Q' w. J/ h# o/ J
        13. #查看profiling
  1.           show profile
复制代码

" h& c$ W4 z0 t7 ^9 n+ ^" R
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

: O3 ]' l; C. b1 q
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

, U- W. g  A+ N" m
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

8 z4 h2 f% U2 `' @
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

  l7 r9 Q; v* W0 T* A2 Z
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

; T+ c9 T* W! i- n3 T2 S2 ^* R! d
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码

" V  x2 B4 R$ r) Y3 r; V. v3 @5 b
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
. H  P0 }. s6 U  m" d4 v3 ?' j
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

* K( q, u# r1 y+ Z) I9 H
   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()
/ _: V" v. P& s& R( z2 A
6.  高级查询
条件操作符
0 b. {4 d+ ]0 l: v0 P$ S, h3 \5 F7 n
  1. $gt : >
    $ ]) D$ t; J2 M5 z
  2. $lt : < 9 Y2 c2 N# ~2 e3 l8 s6 O) n
  3. $gte: >= 4 K" S7 g7 V- m7 ]
  4. $lte: <= # r+ K$ g4 R* |; L  j. e
  5. $ne : !=、<>
    0 d% o0 e1 b% _$ l- a$ T2 }8 M
  6. $in : in 9 k  u. |" F% [0 a  M
  7. $nin: not in
    ) V( ^+ u8 I/ L! N- r* ]' n
  8. $all: all
    0 m& r0 N* z, d! O6 q6 E
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

% i) x& i: E# @/ x  K! `9 c  V- X* Z% z
查询 name <> "bruce" and age >= 18 的数据
2 ]! F6 A7 y5 g! k( ~$ ~# U2 Q' L) a/ }
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

5 \4 Z  |% p2 X* I; e/ z7 u
: E$ ^. t% a1 K% z查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
3 a8 z8 e$ d5 _. R1 v# A/ _4 c
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
' d9 z8 D* C" f" L. A
" `$ `! J/ V' S. t$ M
查询 age in (20,22,24,26) 的数据
9 q8 o& p9 b. A1 l) V# q" O# q9 j
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
; t9 l; P# M. o% I0 l

* y1 J. B# Z. k0 L( F7 L) G0 P查询 age取模10等于0 的数据 ' f" E3 k  a% s* T2 g3 ^* Z
  1. db.users.find('this.age % 10 == 0');
复制代码
$ T3 [9 B8 X& f
或者
7 _( [3 C. g" Z3 J" p
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

! B; H6 @, L7 P! N, u) y0 a
& P3 S, O$ B. |( N! Q$ I匹配所有
- T- U- z7 [% ]: [
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
1 T8 x" f! r+ m. V4 g) C5 T
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } + [, a- f8 Z" m0 B- N3 I) w
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
* q2 u* v1 Y5 U4 Q" }4 q5 S+ z, X: u) S7 f
查询不匹配name=B*带头的记录 ! e: z) c: l% P7 C. I0 J7 X2 J
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

% G0 a9 N; s' x& N' V0 J查询 age取模10不等于0 的数据
+ r* D, s; k. w
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

0 Z5 Q# m( r$ a! ]  C' J- ]7 Q" i& S8 [0 R5 D
#返回部分字段 : V' Y3 j* a9 p- z. \, m5 O2 [
选择返回age和_id字段(_id字段总是会被返回)
; B# d" R' b# X7 M$ _7 p2 y
  1. db.users.find({}, {age:1});
    $ F- m! |8 r* H$ R8 q  c, X; z& {. q& P
  2. db.users.find({}, {age:3}); 6 B- [9 N( a/ I; U7 ]
  3. db.users.find({}, {age:true});
    , h* X6 @9 |- A
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
+ {+ A( A1 C& w9 N* j
0为false, 非0为true 4 V) ^; f" Q4 F5 X2 a0 ^3 u
  g' ^4 p# |! f  [
选择返回age、address和_id字段 % T% {5 S$ G. p8 X, @2 j
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
2 |$ {9 t- T4 _* A  h& {
% U% n( K: A/ u; T3 r+ i
排除返回age、address和_id字段
* q5 e$ L2 x+ E- m
  1. db.users.find({}, {age:0, address:false});
    : V; k0 q! u. q/ s2 O
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
) M8 t6 y& w8 V
' B& ^" {" Z' z2 y: @
数组元素个数判断
- E+ q: k7 B) u# ^+ a( S对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 5 r3 D0 P6 D5 A2 J3 V5 B
匹配db.users.find({favorite_number: {$size: 3}}); 6 m: \% n3 s3 D, x& c
不匹配db.users.find({favorite_number: {$size: 2}});
3 r5 b6 N" q7 W  _. M
/ [; }, E% V4 [! W9 ~' D, A$exists判断字段是否存在 * C3 p0 E9 h9 O! Z5 u1 c
查询所有存在name字段的记录
, P8 F( D5 T1 ^
  1. db.users.find({name: {$exists: true}});
复制代码

7 [5 Q9 J% _3 W查询所有不存在phone字段的记录
+ Z% Z0 |/ X5 c8 Y3 P
  1. db.users.find({phone: {$exists: false}});
复制代码
* I1 m+ e) P. Y
! ]4 u, N' g# o6 S' `/ i
$type判断字段类型
6 [9 t5 ~5 W, a  P, [查询所有name字段是字符类型的
/ O6 c- V# n: ~! t1 k. C% M. R' v3 R
  1. db.users.find({name: {$type: 2}}); 6 _, g) S* A$ _" h& e! x2 n0 Q
复制代码
7 f% Y- I! E2 @0 `7 T  v
查询所有age字段是整型的
7 e$ x" {+ I1 m/ b
  1. db.users.find({age: {$type: 16}}); ( Y7 E- u( G$ j3 ?+ S
复制代码
+ N3 @5 |8 ^9 x, y3 r
对于字符字段,可以使用正则表达式
% I$ c- }" {2 ^6 ~查询以字母b或者B带头的所有记录 ; r& v1 l8 g( O6 H( N- F% i- `
  1. db.users.find({name: /^b.*/i}); 7 x& M  q# R& t) ]/ A& d: I
复制代码
- O2 F8 n5 a9 J3 `7 J$ k' Q' @7 Z' P
$elemMatch(1.3.1及以上版本) + \/ M: I& H0 b* l
为数组的字段中匹配其中某个元素
$ ~  |* d$ F* ]. a$ `# I; `1 {  b# [- Y; p* I+ X( X' v
Javascript查询和$where查询
3 F# f0 g1 I7 N. f1 ^, }查询 age > 18 的记录,以下查询都一样   I+ l/ Y+ l% k* u' d4 X0 ^/ E* Y
  1. db.users.find({age: {$gt: 18}});   P1 J  d# b# m+ V
  2. db.users.find({$where: "this.age > 18"}); # c1 H+ D! u; s) k
  3. db.users.find("this.age > 18");
    ' d7 ?9 ^4 v+ O7 l8 N
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
! w" H3 c9 B+ N" u

8 H9 t+ a* n0 A2 l排序sort() + H  V9 ]" M; w- f5 R
以年龄升序asc $ `$ T7 ?2 J; V( ^2 J# p" Q( G
  1. db.users.find().sort({age: 1});
    , M% g  r1 l. |9 t
复制代码
8 A! V5 `. P* a3 y" S. A
以年龄降序desc
5 }& A( r+ j; {; Z6 A  G
  1. db.users.find().sort({age: -1}); - K( W; X' ^) O2 \
复制代码

+ d$ T0 |" s6 ~, Z限制返回记录数量limit() 2 ]7 ]& \$ s5 t$ c
返回5条记录 7 f+ X) M" j% ~  u) \$ O9 C: B: b
  1. db.users.find().limit(5); / i" i/ w$ ?2 I. B
复制代码
+ q% r& C4 r/ m2 V
返回3条记录并打印信息
" P  V0 w: S" r) U& j& n" z  w( t
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); ' d2 @- X5 a$ E& o( m" b; u
复制代码

% p  Q: w4 L/ [+ w6 w/ S结果
; }/ l1 |. |2 p
  1. my age is 18 # F2 e$ O9 j, V: O! u/ s
  2. my age is 19 : E& \- ^* U7 D7 ~
  3. my age is 20
复制代码
4 D% m0 X. o  h9 h! E
  f* Z4 A4 f; x! s  s) d
限制返回记录的开始点skip()
, g% h6 U) g; q3 K1 C4 k; q2 T从第3条记录开始,返回5条记录(limit 3, 5) ! q& ]0 h9 y, v
  1. db.users.find().skip(3).limit(5);
    8 Z: c! C0 H+ }1 e3 E
复制代码
0 N0 @- {2 y. E* ]7 b, v
查询记录条数count()
$ R& W# m5 H  V) Q1 {2 P: Qdb.users.find().count();
; E- D; b1 `$ I5 p. edb.users.find({age:18}).count(); , ]8 k2 Q+ |; J+ L
以下返回的不是5,而是user表中所有的记录数量
9 m( {( X  j" ]1 P1 Cdb.users.find().skip(10).limit(5).count();
1 X+ _8 d. ]- i$ u- `. s8 Y如果要返回限制之后的记录数量,要使用count(true)或者count(非0) 8 m# f( B$ c3 ]# o6 z' S* H: `. i! M' l
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

( h& C: H8 Q; d2 Y  s3 v. o& Y8 f& S7 d
分组group() ) W" o+ z. O2 `3 j
假设test表只有以下一条数据
5 g, g% b3 o3 d* z
  1. { domain: "www.mongodb.org" 0 L, ]) y* f5 ?* Y+ S
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} 1 ^) Z) b# r! C
  3. , response_time: 0.05
    / x5 M! x9 r# j% A7 E- G
  4. , http_action: "GET /display/DOCS/Aggregation" 6 E, `6 A- k. t. G
  5. }
复制代码

3 L: O) n6 A2 ]% K4 t5 d使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
) A) r$ I% w/ w, k
  1. db.test.group(
    - I7 f/ R5 W2 ]  A+ J/ b1 e7 ~" z
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    * _# |, `8 W( L  K" H+ C1 I
  3. , key: {http_action: true}
    / m6 x6 K& w2 K& k3 l
  4. , initial: {count: 0, total_time:0}
    ' s! z# J' i7 M, _  e2 j5 U( E; ^0 a
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } 8 j+ e0 F# S! \8 p2 s% n
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    % @" P. G! t! \' m  q/ _
  7. } );
    " y& Y. [, q% G' s+ V5 o
  8. 9 t! C) U6 ?# b8 w' \
  9. [ ! W3 B( q% j3 g& S
  10. { 8 l* y5 G. l# v( T* v5 z2 O
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ( I: _. E% ?6 m/ b* l. I
  12. "count" : 1, 4 |3 L! C3 ^8 o; T6 ^$ |6 J
  13. "total_time" : 0.05, 2 d& }% O4 E) y$ F- h
  14. "avg_time" : 0.05 8 r& g$ A% \. V
  15. } 5 W! y' H$ S3 U; T" B
  16. ]
复制代码
# F" {3 `. @  P# K, p6 J8 P+ ?
+ }( Q5 V- M0 [# U, \! K& @

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

) R9 f. I2 A: B0 r% G) b* ^& z  t- y% B, K2 _8 X

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

' w# e: G4 q: g0 s9 e7 w! Z! T6 ]" O' C8 M* M
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
; g+ v5 h6 q9 k

& W) s4 {( A$ j) s9 d* [+ l  z# c
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
3 F; ], q, p1 N/ h7 Y7 m. l

: j2 r2 T9 |; z" O! t
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

/ E% O4 W- a1 L$ V* `9 H
3 C1 v/ Y  P5 l% T
输出如:
  1.         
    ; G3 J0 o- ~' V  X8 E, u& E
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

7 b) m) ~* _9 k9 H% A6 L% M+ L7 P7 V/ z. y( |6 [7 c# j

* E; p: |6 Q" i
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    - P' u3 n) q: X
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/ u+ b- a! x" S: z! D6 i
  3.        xmlns:context="http://www.springframework.org/schema/context"$ S1 n9 `# l; B3 X- Z( z3 G
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    7 E1 ~" Y6 C: U/ N# \0 q+ g% m
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans6 ^7 U8 s0 v" J/ @9 R$ T; Z5 Q7 ^
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd0 x$ E4 {  l5 W
  7.           http://www.springframework.org/schema/context! K" C+ n. ?- F# T' M
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    9 y  P5 P. x( X5 ]" ?% O5 p
  9.           http://www.springframework.org/schema/data/mongo$ J4 k; B) ~) P" H0 ~  n
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">% |0 Q+ O) T. G
  11. " ?: ]3 X% V) X9 r2 Q8 X
  12.     <context:property-placeholder location="classpath:mongo.properties" />' Q' K  j* J! ^9 {

  13. 7 D! c# {% G. K  U4 q
  14.     <!-- Default bean name is 'mongo' -->
    $ D; l% b4 `6 c, p  ^0 P) v9 h
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />. K7 h6 T' Z9 @+ ?- t

  16. " D7 k5 l+ m6 P( I' [+ U
  17.     <mongo:db-factory id="mongoDbFactory"- z+ V) w6 C1 d1 z% u
  18.                   mongo-ref="mongo"% }& v" {5 d3 F9 w& B/ z
  19.                   dbname="mongotest" />
    / v$ Y9 k: @3 a( X9 k+ f( ^) h
  20. ! O4 L. T% k+ B5 L* K
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    ; L/ C1 e+ F& E, H
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    / n' d* F& Z9 y8 L. v% |' [9 z
  23.     </bean>' ]$ G2 i4 i! B
  24. </beans>
复制代码
4 c; A$ H  U9 b  y
7 H+ E. X$ N' E% ?
maxmin的测试
  1. @Test' {) i8 H* L0 A6 S/ n- @+ M  R" l
  2.     public void testMaxAndMinAge() throws Exception {8 B0 R2 z( J( a, K
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);5 g/ G% d; e! p; D/ T
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    6 T' }7 g& O* g! M+ `" U8 @
  5.         log.info(result);1 e6 J) s. B# w* i9 p1 @* I
  6. 1 o2 T5 D$ ?- Q! H" G
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);' n8 d  A; E0 M( j% Z
  8.         result = mongoTemplate.findOne(q, Person.class);
    5 v+ y- G  Y1 j
  9.         log.info(result);
    # F- W4 j* w( M! t, j" m
  10.     }
复制代码

$ M( h8 a: L  Z; Q1 [2 W9 U
4 {0 Z2 T9 T( M; K. W
distinct的测试:
  1. @Test
    1 \: {- o# f9 [/ V2 B
  2.     public void testDistinct() throws Exception {( ~; }4 E1 e! [8 g& @
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    , v( x) {' \. A' g' F
  4.         for (Object o : result) {7 H# U- a: i. {( v
  5.             log.info(o);
    9 P; \$ i' r: Q5 ^3 d$ i( Y1 F5 W
  6.         }
    ) `! r. g3 s8 k, U5 w

  7. 8 [9 b& l% O: X+ G4 R# _( _$ A
  8.         log.info("==================================================================");, }6 I, Y6 }: }: N% k* e9 [
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));8 ~$ @+ U7 Z. [7 @- r
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());# o+ z5 B0 a' ~9 j- s2 K. M7 U
  11.         for (Object o : result) {; Q- ?. e( k" s
  12.             log.info(o);
    / l5 x. D+ i5 Z4 r( w
  13.         }# x! K. V/ _, m$ L, O0 K

  14. , S1 l( ^+ ?- u) z1 i, t
  15.         log.info("==================================================================");' g1 S' Y+ C1 g+ V
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    ' T: K5 N: N! X0 Z6 B
  17.         for (Object o : result) {6 C; T& Z' X$ W0 P) w! U* i
  18.             log.info(o);
    0 r8 H2 T7 i$ ]0 B; _
  19.         }
    ) J; i/ }2 H7 X! s. _" Z* A
  20.     }
复制代码
. B# g& r1 L) S& S* b6 t
6 W6 ~* P3 D: ~( C8 v
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 2345678 s+ S. X  Z" I4 E: R5 C% a7 j
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678; p7 Y# ?' }: O" c- m
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789$ B) R7 {7 J4 R6 W
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654% Y8 O  n2 S/ U' t. U4 j$ D* C) z1 \% \
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    ; C' r/ j" G( i; e+ }
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    / ^) Z# V2 v* u2 G
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    " W4 q& A3 P* [# e
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    0 g6 y( {9 [* w
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567* U2 [, Y5 L9 Y( y
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    / @) G1 @2 O% r3 j! J
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789% Q" b! M* o+ z# e" i$ Q% q
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654; m: T+ z% d( e$ A9 v
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================5 h# g3 P; i: V* \0 [/ t* P1 ]0 s
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    , x2 E, i, I7 d3 C. O
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    ) B' A- @- J1 n  ~" x
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc. A( w4 N) E& b2 I9 B" r
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www; F1 z& i9 x) {. S" f! q* f
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    9 @# r+ @3 |# k) B
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    6 m5 _/ W, R8 z" Q, J
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    # V; E, M# |, e- r9 S
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr0 h5 m2 Y5 F. Y
  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
复制代码

) \/ ~3 S" _" Q/ U3 A! d; R0 Q7 u7 }! ~1 x" g, {! D
这里我要特别说明一下, 当使用了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等信息。

/ [  o! h9 x1 ~5 Z# ~1 I
1 `9 {& r* A% r9 s! _2 {2 i# ^" g3 ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:54 , Processed in 0.064975 second(s), 23 queries .

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