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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:: {+ T, k( ~2 k7 d, Q6 i4 g

5 b5 E4 s" D3 B% a. {1 ) . 大于,小于,大于或等于,小于或等于  X6 ^, l  }, \( O3 W

, E! T' L  {+ C7 i# v$gt:大于3 x8 m; T: G6 p
$lt:小于: o" b  J$ V  M3 }) L
$gte:大于或等于! F" r# T3 L; s" U0 B' D3 r
$lte:小于或等于1 V( l) r4 A! Y9 i6 j
. R3 A1 Q3 ?# Q$ f; K1 R
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value) T2 C# K0 F7 N( z
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value& I! p0 D- T9 H) ^% ^
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    $ |# [) e6 ^7 j6 g2 O
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
* [3 F& `' o& `! e" |
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    2 E) n5 [2 Z% \+ \8 y' ~1 I
  2. db.things.find({j : {$gte: 4}});
复制代码
/ |. E/ ~  o$ E3 x# R: J
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

. k0 y2 R- k0 U% B9 X# s6 T) _! R1 c% h- ^7 y( M5 x2 E. W) N9 f+ F

5 M( J! Z! b- `; a- _
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

4 F9 C/ U( X) `* A0 u
3) in 和 not in ($in $nin), ~: H% `; t* A4 m: t8 A" P- z

1 b7 W3 w. u( O语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
0 c$ z4 P2 g4 y* ]/ B* l+ z% b
例子:
  1. db.things.find({j:{$in: [2,4,6]}});: a4 [+ K7 K. n% |
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

/ c0 i9 ~$ K6 ~% z( J1 o

6 f* N: z; O* S3 G% M4) 取模运算$mod- p6 w; E, c6 ~! s) _5 v
9 n. }; x( G" K* X
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

: C6 ]/ P- M! P2 _/ h
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

, T$ I8 l7 f2 J9 f1 o  {( Y
) F  l7 q; V! d5 I4 ]* c
5)  $all
, x8 |5 @# E& S! _( m5 u8 |
5 w0 I# L7 g1 C4 ^4 e* |$all和$in类似,但是他需要匹配条件内所有的值:
3 E2 U' u7 \# R: r  Y$ q% _
! J6 \9 I/ b  q& y6 U9 t. a如有一个对象:
  J' o: ?) O) K1 g+ c+ ~
  1. { a: [ 1, 2, 3 ] }
复制代码

* N2 C7 ~6 J6 D  s4 t/ a
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

( B: _0 F% U5 I; P4 |
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
) j2 B, R; T, |4 Y4 v

# w7 Q% A/ Z* v, `6 B8 S6)  $size
$ L: K! v. ]1 }/ W& |3 y; j- l/ \& X; b  ]6 s+ j
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:+ C6 Y% A8 b2 G; {5 Q
: g. u3 K, G( `' H9 {2 U
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
; O4 S3 |) O6 M. Y  H- W
官网上说不能用来匹配一个范围内的元素,如果想找$size<5之类的,他们建议创建一个字段来保存元素的数量。
You cannot use $size to find a range of sizes (for example: arrays with more than 1 element). If you need to query for a range, create an extra size field that you increment when you add elements.
6 p6 m' a! y( n) N1 ]
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回' ]8 a8 R2 j* Y! F# e) @0 G
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

; V1 [1 h$ f9 a: @3 r0 W
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    7 V8 I3 o9 l4 F- N) t; L/ G0 s( F
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
, @: z# k1 [& k
9)正则表达式
: z8 w8 ^7 ?! Y( `' h2 M- l2 g" e' i6 g
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

  ^6 M, d, s* u
10)  查询数据内的值: Y  b+ ]5 c+ Z
4 z' Z" x2 X0 G. l; ?/ o& X
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
" W* [4 D. _5 f
11) $elemMatch) U4 s: \# K$ |; k
- D; a/ q- s; }. \
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 7 G2 ~9 w, L7 w* i
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    6 p) T* n+ Y0 k. z# f: k( \5 ]- i
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    , l, k/ ~9 d& X' B  N2 |3 y. Q
  4. }
复制代码
( `: V% I0 a& s( i. T) a1 w" c
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
5 ]: ^: T7 H; x# x; E3 N
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } . f/ k3 C. c; t6 V" w% T. ?
. ~& d$ M# b9 b7 W# G) P0 A
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

& a) q/ W) G# f
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
% R. j4 {7 K. K9 t* u- v
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

/ c3 ?2 e2 s" e5 Y2 s( P% ~& F
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
4 A: i" ]# p% m* u2 d+ @
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

% ]  ^/ t# H. d- Q, T
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

/ A: J8 e4 E6 ?/ ^+ k- C) K
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    - U$ A+ O6 D% n: |
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
* r5 p9 }2 _3 J- @$ E. r  B  g: e
mongodb还有很多函数可以用,如排序,统计等,请参考原文。' x9 z5 {' o6 {4 |5 d3 |
/ M7 n& E, k$ c0 `% A7 N+ o  D
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
  r/ D2 x# Z* T6 m8 X3 d! F% @/ a1 E* U
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
: B& o$ P# `: e  k1 C  r: x* f1 w/ a9 o  ]$ B5 N& h
版本二:9 F1 ~' X( `. G! p: |
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
$ L9 y! H3 o7 y: d$ K5 ^
  1. use admin
复制代码

; A( W6 Y8 x. X
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

7 a0 R  X# k2 Z  C% H4 J8 W
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
7 N: d" i4 b  Z+ w
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

) k+ s  M2 N4 m( t& Y. [
         5. #删除用户
  1.           db.removeUser('name')
复制代码

6 m) y' s, I9 j; u
         6. #查看所有用户
  1.           show users
复制代码

6 ~/ d8 V3 Q) B- t( o2 }4 D' }
         7. #查看所有数据库
  1.           show dbs
复制代码

' T/ B1 K$ N3 _' X/ e' h( @/ M9 h' N
         8. #查看所有的collection
  1.           show collections
复制代码

# X4 G) ]2 f6 O( T5 E
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

9 I5 X9 w* n  w  @# [: f, ]* G! x
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

) ^) Z7 p! I4 T" f3 j  U+ J
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
+ X4 ]+ n  o: t, {4 ^2 j
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
4 ?- g  [  m& q4 m# T! O+ I- t
        13. #查看profiling
  1.           show profile
复制代码
( {4 z1 F  x3 V9 X/ O
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
* h2 T, G5 |- K2 P6 j! ]7 n) Q0 a, J/ ~" U
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
$ ?# q/ l6 f6 N5 F- ^1 _
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
$ s2 K" Q1 P; X8 Z
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
+ X! B8 R  ?* v3 U. q! p, V" r' U# ~
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
- x9 K5 M6 d+ L1 K
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
. X' R8 [- r. C& {3 u
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

' _: M% `  x% `+ M+ p
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

9 }/ V: x2 M2 e/ Q* |/ g& [
   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()

: Q% n) v/ R6 k+ L
6.  高级查询
条件操作符
0 f; I' K% a+ r/ T+ n0 P( X+ t6 b
  1. $gt : > # [9 L2 \( H& E' x0 C
  2. $lt : <
    9 T0 Y( ~! P. e- Y* y5 d
  3. $gte: >=
      A7 T5 v; G+ @! U/ l
  4. $lte: <=
    5 J5 E2 x  Y* s) R: n5 F
  5. $ne : !=、<>
    % o+ K* @  K; Q  x
  6. $in : in
    - X3 A) e' u3 p7 f& G3 L4 R8 \2 s, s
  7. $nin: not in
    1 r9 O* a- m( S9 z
  8. $all: all + [6 m, i) v) p0 G
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
" u7 [9 `/ C7 w) q

( ]: b. Y; S. z查询 name <> "bruce" and age >= 18 的数据
8 A5 r& `( Y2 E" x( g
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
9 T5 _2 @" E9 f) P6 ?

& y- o) i# `" o+ \6 H$ Z! S9 P查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
3 b7 M+ D' }2 T) U
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
& |* F* \. J  y6 b7 x1 [+ e8 j4 ]" O2 @
! m6 s% O" g/ z! @. X% ~
查询 age in (20,22,24,26) 的数据
0 l5 Y+ a8 b4 K3 O0 u; N' `; n
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
; H6 j' G; O3 ]! p; X: X: Z1 l* j0 ?6 R
0 u; T5 q1 ^3 B6 g
查询 age取模10等于0 的数据
. d( T. O* a$ n0 e" G8 p" `% O0 U
  1. db.users.find('this.age % 10 == 0');
复制代码

# Y& ~. O# [: `1 ?/ B% I: \或者
7 p  z0 ^7 ]5 E7 u
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
- y, w2 G: v: [
2 T1 e$ p$ k% A+ \5 M+ c
匹配所有 ( m, O- j: g( ~, e# ^, _; t! ?
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

1 s; {2 |% B! W2 x. Q4 H* f: ~可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } 6 N- w. T, L5 P% f' M" U
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
8 t! p; i( G7 h
( Y! p5 e* o- u* G1 j* I0 ?% U查询不匹配name=B*带头的记录 3 O9 H6 D% i$ ?1 U$ {
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

- |# J, ~9 l" i9 f0 |' p9 [: H3 a查询 age取模10不等于0 的数据 ! v- V. g" @! N' f8 }. Q
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
) k8 E/ u1 t1 @  L4 H5 ?$ w

( l* P- i. ^  e3 O! u( I' M3 n#返回部分字段
6 O6 a; C+ l! d5 K  ^选择返回age和_id字段(_id字段总是会被返回)
1 l2 a$ m6 y( g! ]6 O6 ]0 Y% Y; D
  1. db.users.find({}, {age:1}); $ e) U8 P+ \' Q3 b" Y' C( \
  2. db.users.find({}, {age:3}); + Y/ y- E9 Z( q# O- \
  3. db.users.find({}, {age:true});
    : `3 I. A- g& }  o" a- v3 x! s
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

7 Y9 W/ Q9 `  r: q& u& ^8 N0为false, 非0为true
4 ]1 \6 {! t7 l4 X# n  R3 K  O
, Z' {( n5 y5 G! {) n2 {选择返回age、address和_id字段
7 ~# f( f6 h4 n! E3 e
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

7 L* m; x3 V: W! f9 ]
9 c0 D& I# E" F1 b0 E排除返回age、address和_id字段 2 J4 @0 T* o1 p9 {) K8 G4 J( n
  1. db.users.find({}, {age:0, address:false}); : h; g; |0 L! O7 ^- G# c$ }, f* l4 ?
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

0 Q! h& M7 O* V
' W5 v) B' D9 n0 R) _0 a3 q* P+ H数组元素个数判断
' g+ [8 N/ }& `* l' ~) M对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 1 N7 {+ y# o2 ?: S7 @& y4 [
匹配db.users.find({favorite_number: {$size: 3}}); ! I$ e$ j* e4 V  h* w# d" m$ @
不匹配db.users.find({favorite_number: {$size: 2}});
, J+ y5 y. G- u- H! V2 f& P4 y8 W! L
$exists判断字段是否存在
& h' l- ]. x8 p8 L0 I0 E& ^查询所有存在name字段的记录 ) r8 @2 z/ q$ E3 _1 R# Q
  1. db.users.find({name: {$exists: true}});
复制代码

3 M% o' V% {% w& {查询所有不存在phone字段的记录 7 J0 Q  ]3 m$ A. S- l, U1 E
  1. db.users.find({phone: {$exists: false}});
复制代码
( J5 I9 Q: n! T1 g# N
  X, p4 ^& [) U5 A! Q' {) o
$type判断字段类型
. ], A( c: b7 d3 d+ `6 Q查询所有name字段是字符类型的
* w% O3 Z9 M4 U: m5 ^
  1. db.users.find({name: {$type: 2}});
    # s2 k& T& Q3 @/ r9 }, b
复制代码
8 O% [' c$ N8 K/ u% U5 g
查询所有age字段是整型的
) m$ Q" g  B  A; H2 z
  1. db.users.find({age: {$type: 16}});
    . _  \! u( \. H( A: U
复制代码

' F( Q# k  v, s( e  Q0 W对于字符字段,可以使用正则表达式
$ h( y* n: A; S( g查询以字母b或者B带头的所有记录
  ]6 k: N4 [4 [4 f" Y* Y( e. F
  1. db.users.find({name: /^b.*/i});
    8 Q% x7 K8 i, e( ~
复制代码
/ Q4 s$ O6 d; ^$ e
$elemMatch(1.3.1及以上版本)
: ]8 @% i! g; `. ?1 e1 r为数组的字段中匹配其中某个元素 ( t: @1 b6 W! p. K

7 A. w1 _# v; H0 S1 I$ lJavascript查询和$where查询
% J* O1 s" ^& ]4 ^- W查询 age > 18 的记录,以下查询都一样
/ e, ]" F5 |3 p) B2 |' Z/ a
  1. db.users.find({age: {$gt: 18}}); 7 u$ O; ?: S7 m. y
  2. db.users.find({$where: "this.age > 18"});
    ( W* T( U2 B% ~1 y$ Y7 \9 O$ B
  3. db.users.find("this.age > 18"); : g7 N% p! I. `' x. T2 S, \
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
4 w0 X# u8 z9 G# Z; N

5 W1 [7 l, c* u8 F3 ?/ |- O排序sort()
: Q3 _% L9 J. D/ U以年龄升序asc ' T* {2 M' @* j
  1. db.users.find().sort({age: 1}); 5 ^1 [% `, ?8 G4 o4 k! O5 r! M
复制代码

& s2 q  {2 j/ D$ ]以年龄降序desc
4 P) E9 H: R9 S3 d% T8 R5 B7 S
  1. db.users.find().sort({age: -1});
    # F/ r: d! W% J( j5 a# @
复制代码
6 x* ?4 o  o3 B  D# B" a3 D4 W7 E
限制返回记录数量limit() ( R6 W2 v9 A, r7 v: Y
返回5条记录   e- U9 z( \% J" m, G
  1. db.users.find().limit(5); % _7 n1 Z, f, K
复制代码
+ s6 H" V; ]( p- _
返回3条记录并打印信息
7 h+ D( {! n$ ^* o, B% O; }) l  K+ Z
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); 2 y! i2 G# F3 ~1 C4 p
复制代码

) K7 m. f2 m+ ]3 h7 a结果
+ V0 j/ h, M& y' R3 d+ ?
  1. my age is 18 ' O) {+ d! m, }) g& N
  2. my age is 19
    5 f: J# H0 ~1 O7 K! o2 A( ?/ `
  3. my age is 20
复制代码

; q5 `2 G3 i  ~; J$ Z  l7 C! i; k% c( G6 z
限制返回记录的开始点skip() 2 o/ Q2 d* |; y
从第3条记录开始,返回5条记录(limit 3, 5)   h0 H$ N+ c- @$ u+ X2 U, ?# t  N6 z. X
  1. db.users.find().skip(3).limit(5); 3 M5 A& X' j. t5 ]1 X
复制代码

  d1 w4 ?- A5 H% o查询记录条数count() 5 w; [- W- j# s* R
db.users.find().count(); & ~5 e* |  o8 g
db.users.find({age:18}).count();   ^  f5 ~- ^; |
以下返回的不是5,而是user表中所有的记录数量
" M7 h  v& o) ndb.users.find().skip(10).limit(5).count(); . k# @/ F  r( E/ |
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) " C& ~' Y1 m4 r6 Y7 z  P. w
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

/ h$ R& }9 V* @1 p
$ k) e# M: g4 E- @! `分组group() / A8 f- B2 p# i; a4 N2 Y0 k/ t: W
假设test表只有以下一条数据 5 P- `9 e0 ~$ j. A
  1. { domain: "www.mongodb.org" 5 P! O: q5 F( [
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ! L& n+ V! ]1 \- D8 k, u0 J' S
  3. , response_time: 0.05 * N& k! @2 G) Y+ W
  4. , http_action: "GET /display/DOCS/Aggregation"
    ! r: o" R. d! N* A" E  k& ~
  5. }
复制代码
0 a$ e$ C( D* C. z# R) T
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; ' h, o* u/ U4 E" c
  1. db.test.group(
    * j' p3 D; R& J: Q4 k" c# u
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    3 d8 {; Z8 z8 E1 s( J: X- [
  3. , key: {http_action: true}
    ( v( v5 w$ E7 c8 j3 {) \
  4. , initial: {count: 0, total_time:0} & {3 K6 D# S1 t
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } 0 e# H+ j0 J4 f  w  M( ?, i5 c, `* B
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } ( t9 z, }" ^% J! z
  7. } );
    + o0 e" ~) S; C: ^7 `4 l9 u
  8. # g$ k! m% O& J% h
  9. [
    & |1 r0 u  J9 b0 h
  10. { 8 h  @. Y$ q( Y. H3 U- A
  11. "http_action" : "GET /display/DOCS/Aggregation", 3 H  O$ v7 L6 r# O! \& {2 l7 w
  12. "count" : 1,
    ; K" n+ M5 M4 [3 w# H6 m3 J
  13. "total_time" : 0.05,
    2 e" f; f" i2 ]5 H& ^+ e3 a$ X
  14. "avg_time" : 0.05 9 b" p: X$ d/ H% Y+ D" e
  15. }
    % M) f$ e. A3 ~3 V  [3 ^2 i
  16. ]
复制代码

) K. \" y3 F7 \0 n+ I4 l
. T) a; v7 N1 z+ T
* P. C/ T2 I$ A0 cMongoDB 高级聚合查询
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
    1 P1 D4 X: m; p0 k' C% ?
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

/ d1 g! p$ F1 U2 U
. A, e, H8 ]$ ~! E& U

/ U7 \) L9 A9 r& s; H& H0 W4 O
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct8 R1 z: r- T& m7 [$ f
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
2 J+ h9 b; l9 l$ M1 t

: h# S/ ~  X' y" t0 H" q
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

/ ^  k5 k. q( H  c$ U# g: i3 A" O3 W" Y# ^$ O, W
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
) r6 r+ X2 N/ p; X
# ?- m. x. s# o9 a; t  S
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
0 I; o- K' ]+ S0 C. f5 \1 ^' L

, z0 H9 A+ u$ d  Y9 i
输出如:
  1.         $ y) X& N5 c% [" Z3 `/ L5 B; Z
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
. d; P& y& g' q; }

3 I, S/ v2 U; \3 s& m  w9 ^# w+ @  ~
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"6 r/ H( _: f) f
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    7 S0 |9 `1 _; g6 C
  3.        xmlns:context="http://www.springframework.org/schema/context"
    , `7 q: v8 Q6 W7 ?  @& z6 U
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"( q& ~; I: s8 C
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    ) e$ ]2 L! Y2 F4 ^3 N: T+ T6 v
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd6 J3 d# ?7 y) L$ G4 w
  7.           http://www.springframework.org/schema/context
    2 V+ Y8 n: [. l. a* H! E/ C
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd" i- s6 y. _4 K* I! U4 Q
  9.           http://www.springframework.org/schema/data/mongo3 n* _0 U2 }7 E
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    ; E. @* t- U6 p5 i8 Z
  11. / H8 l  A9 G, H: f# M
  12.     <context:property-placeholder location="classpath:mongo.properties" />+ p/ M; [. [8 a2 Q! c; t, d
  13. 5 D$ G( M) [4 w% w
  14.     <!-- Default bean name is 'mongo' -->
    ; [5 L$ z; L7 P$ y
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    , j0 p) W8 E# z- p9 [, O8 U) s; p3 t
  16. 4 n* ^2 z2 V, Y# T
  17.     <mongo:db-factory id="mongoDbFactory"( R$ F' O# z8 Z/ l/ g% W4 r
  18.                   mongo-ref="mongo"
    $ m+ g  |8 c$ c( i' t, b3 K
  19.                   dbname="mongotest" />7 U% f! S9 Q+ e! g% L
  20. 7 N, }* P0 G/ c+ D, h' K5 f3 {7 t
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">: O4 N/ P/ c" b- l# t8 Z9 P( D* r
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>8 a  P1 e/ }5 \5 _( f( I0 v
  23.     </bean>
    ; [. ~% q- y- N" ^" f$ ?6 o4 ~* U# T' g
  24. </beans>
复制代码
  a2 T8 Y! {& N7 L4 u: {7 Z1 z) v4 `) |) {! C

( o$ I' L/ Y6 W* L5 k, E# G+ R* p
maxmin的测试
  1. @Test+ O3 i' s1 v9 r( Z
  2.     public void testMaxAndMinAge() throws Exception {
    ( ^% ~( B, P- }
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    0 x2 J0 @& B! F0 j9 M
  4.         Person result = mongoTemplate.findOne(q, Person.class);. p; l( l! U2 M/ L7 w* i
  5.         log.info(result);
    . G! N! g, J1 M# J' X
  6. 1 |! A$ a3 C* w# `1 k
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);; X0 x: f. l' J- G2 U5 y$ G+ o
  8.         result = mongoTemplate.findOne(q, Person.class);
    + V5 Q9 S* z/ b6 F- Z
  9.         log.info(result);
    * ]% D' `5 V" _9 Z0 i
  10.     }
复制代码

2 Q$ ?/ W: j3 a+ g2 K" W$ M
% N( P# P! @' ?' a! @
distinct的测试:
  1. @Test
    * w9 C6 x: D8 F" k! Z
  2.     public void testDistinct() throws Exception {
    5 `; N4 I/ c2 k/ c& g! C# |
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");" O2 H4 u% Q/ f5 I3 D2 o
  4.         for (Object o : result) {
    * ^, [+ X3 N! G. [2 c6 m. l
  5.             log.info(o);, C4 B" l6 n" I# h3 p. Y
  6.         }, Q& {& W2 g! M4 u

  7. 7 ~1 U6 @" T1 V4 ~6 I6 V
  8.         log.info("==================================================================");$ i& O! I6 k" u! Q6 X
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    % K# [2 ]. }, {% O
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());4 Z- @7 [5 L% ~
  11.         for (Object o : result) {; h8 S# Y& Z8 L" C
  12.             log.info(o);$ x6 p# G. ]) J; E% L
  13.         }' v9 t- `# T/ K) c' x

  14. + k1 t; c; a% ~! L( U3 x; E
  15.         log.info("==================================================================");; y& _5 h' P# V* }$ F' q$ O# T5 c
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    , }# G# n. n, ^5 |- p
  17.         for (Object o : result) {
    $ q4 G8 Z7 }4 P
  18.             log.info(o);1 h( K; t9 Z3 U
  19.         }1 z1 Y9 ]7 [( m6 c5 a' P" [6 l8 e
  20.     }
复制代码
" V! U$ m& z3 T6 {

% f3 S' N1 l% k# r& w3 F
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
      S; x" v, s* W- i% J, P
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    1 z* U: ~6 [% {  d5 b" V/ i
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567895 Y$ H) |6 k  B7 B" }
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654+ b6 ^, s8 [1 B6 p- ?1 t( J
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni' X) q* Y5 B$ w
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    ( h! n8 C7 K/ k3 Q* n. `1 j
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456( _/ p1 [: ~& P& [
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    - U6 |% F( ]! M' h
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 2345675 K- J+ n7 X9 h7 L' @9 y
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678/ }$ u% }2 m4 w( E  p
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    8 Z- s; i9 N9 @- D: X
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    4 g4 @: x5 `4 [( ]6 F/ P, L! \
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================$ K% S& q" L# b) k. f9 w
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa: ~1 r* d2 s! @9 R+ y0 h
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb- y3 x) n3 _# Z) T
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc4 X9 s7 J+ K1 V+ [) S
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www9 \( ]; F* m% x; O
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    4 m6 n' ~! z- ~) J5 g/ o3 |
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    4 @0 L/ M  n, ]4 K2 P) F7 G
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    + Y  E- J; g1 y
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr! [- r% y# S3 ~" T) X3 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
复制代码

9 I8 {- R) i0 a8 f6 p9 q  }0 y+ v
9 k4 g+ }# o/ _5 n, _
这里我要特别说明一下, 当使用了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等信息。
: m3 }- i, e6 |3 x& P, S

1 f; {/ [5 b- u% X* b9 c
8 R+ S  k8 [& o$ ~( x% H
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-9-28 06:36 , Processed in 0.145604 second(s), 25 queries .

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