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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
版本一:
1 a. d! R+ P, ^6 V
, u0 S2 E1 q9 R0 ^2 g/ Q1 ) . 大于,小于,大于或等于,小于或等于1 h0 F) s6 E5 m7 q" t

$ |* P6 f" u$ X' E2 {$gt:大于7 X8 ?) n4 H1 J4 o; i$ G3 p6 I) o
$lt:小于, Y# ^" Y5 L1 g3 F* w
$gte:大于或等于
! j9 b1 G$ {+ ?3 E$lte:小于或等于- @& f6 D0 b2 l
& D, j+ h+ b% r# m) K8 b5 S
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value. F6 t- Z) Q. o6 S, [
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value6 W/ |/ w! }0 a6 X' I4 ^6 y
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    + V! Y- o# ]$ Q# _. c
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

3 ?9 J9 G6 X' e/ g/ i
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    , A: M; x" \5 d/ J( u
  2. db.things.find({j : {$gte: 4}});
复制代码
) s1 z+ s- Q) A7 X8 ?2 {9 m/ }1 u
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
2 \' l3 j4 @9 }- A, g
9 @2 K# U2 p# q3 d
! z8 Y( V4 Q$ I4 `$ u, m) b
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

8 N  H9 z  E% v) G% ~1 o
3) in 和 not in ($in $nin)
* s7 }1 D! R/ S8 c! L/ Z" ^; D& ^2 r  `" b1 K
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

; ]2 v% m6 ^; G2 _
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    0 {1 l; D6 t7 `
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
- I2 s* Q6 E$ n" Q* u6 j' `; g
4 h: ?8 J# N. d  ^
4) 取模运算$mod& \# v, M/ ]6 v2 j# X

9 T& ]- P6 B$ V+ x/ g如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
, u+ Q" Q3 _, H7 G8 @( y6 _: c, Q
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
! G, Y( e; n: w9 J6 I$ `

+ u: M$ B' |  R6 R! }, H5)  $all
& Z& u+ Y) b& Z6 {4 E7 Y" m9 ~8 c/ z. E5 L! O3 {6 [
$all和$in类似,但是他需要匹配条件内所有的值:
' Y  Y- P$ q* e0 Q+ m
; m( a# v- V5 |; _& y如有一个对象:
/ o: C6 x, k% i
  1. { a: [ 1, 2, 3 ] }
复制代码

7 e9 i7 N( b% y( y$ Y0 ^
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
+ V" f8 C* X% u+ f: s- K
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
6 r5 C' P, K. Y8 G' U4 l
& i: a& e3 P7 h  Y: B! r1 l
6)  $size
$ D, A: k2 O) B9 @+ X# P+ T; N2 z. v  ~6 l7 J
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
0 {! M3 l' T3 A" E& h, e( x% B6 i5 K7 S/ [
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

+ ^0 W2 w. m* x- {" D
官网上说不能用来匹配一个范围内的元素,如果想找$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.
: D' \, X1 {' y$ J" C) L# C8 a2 E
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    6 S3 S% J) b# }/ p% j' ]
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
2 K6 P- w! F6 V7 Z
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    & H0 O; ?- }% j, M; e, Z
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
% ~: j( |; h) J
9)正则表达式
3 T2 n8 J1 B' H) P
6 K5 G( p- \+ B% F/ [mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

0 }3 {& L3 w& Y) v+ S# ~$ q( ?
10)  查询数据内的值
3 q2 i" H' O: j" B
0 M0 t! O. y% B8 v' a4 V& i下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
( A0 ~: R6 i! R" C" I/ V* B5 M
11) $elemMatch5 d/ D+ j& {1 A

: s3 M- @( ?9 F3 ?9 ]如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) * ?0 O4 ~; v. C$ {4 F; Z$ c2 l
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    7 I1 r% }' S* W) z  R
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    4 ^8 x  u* o( t9 h
  4. }
复制代码
0 S3 k% p: Z6 y+ P, K9 H
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
" W( f4 h2 h( r: K1 _7 {  G/ U7 ?
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
4 M2 k" l/ }" k# J4 Y3 _6 D  Y( ]5 c
2 Q* j7 F- b) l2 m' g12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

4 a+ l& g+ U6 q. S8 z% b
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

' X  r4 J8 i) W7 w: ?+ H
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
( t) |6 s4 `6 ^8 Q
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
# [4 m9 q4 i. n+ f# R. x$ h  b
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

2 l- ?4 W  [( o9 o
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

6 @6 j/ \6 F/ f8 ~; K3 N
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    & a! N9 i0 O; g" x* h
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

, ~) D8 h/ v2 ]3 A! ]- Q
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
1 _8 N  j6 s: R2 l2 P. c8 ]" E! p& E/ U" `/ S1 f/ p# K
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:1 ~. m$ r. x! C

/ P5 r, q: F: S% q" ]! C9 u; uhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions8 ]0 `. b* p3 `$ a& ^

, d4 Q4 @- s1 x/ G版本二:! T  V1 A2 Y9 U, C/ K$ `- F, r
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

2 ?) H2 u  E$ K9 O* n# K. `3 X9 b0 D
  1. use admin
复制代码

( |( l& E  q5 f4 d4 V
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
! X- }( K) f# I9 V+ r9 B
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
( @; b$ U9 c1 @, G3 ^7 }) @) I6 w
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

3 {# s( P$ X' z; S
         5. #删除用户
  1.           db.removeUser('name')
复制代码

7 N2 z" n7 y& i( L
         6. #查看所有用户
  1.           show users
复制代码

' `7 \; h0 t7 Q
         7. #查看所有数据库
  1.           show dbs
复制代码

% J0 ?* \8 S2 G3 m3 {. w
         8. #查看所有的collection
  1.           show collections
复制代码

% ?  S" _  i' u1 I2 c
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

$ C) s9 D2 Z/ `& q
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

) s; b: @* A( O8 k
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

0 R4 J2 H6 P$ w; b0 P" W( B' w/ @, s
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

+ l6 Q% h1 x1 G7 U5 L: C! f
        13. #查看profiling
  1.           show profile
复制代码
$ b7 k2 c, Y: m$ J, I2 q+ f. h
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
  Q4 G0 x7 y. x9 Y  r
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

! _! F& L" q! J( G6 v! I
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

  F6 H' v  z# k
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

3 n3 ~2 E8 V8 a$ j  L
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
+ G$ L8 R! h2 p# w6 q5 g, u4 \* o
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
7 w) g5 m! o/ n, E$ ^8 z/ h7 B
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
6 A: G1 H0 O5 [# Q$ g0 n1 V# @
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

$ v8 g9 w& C' g0 V+ H* o
   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()

- y: i# ?8 r, G# Y" J# P0 y0 Y
6.  高级查询
条件操作符 ) u; \3 K8 _$ y4 u, J2 H
  1. $gt : > ' U! R  f- T$ [3 G) K) B
  2. $lt : <
      a4 Y+ Q* c* F# I3 d" d- L0 O
  3. $gte: >=
    - M2 v7 h" M1 P6 r- n$ P1 x9 `
  4. $lte: <= 2 Q& ~1 ]4 X/ v. m# {; j0 W
  5. $ne : !=、<>
    " c2 o( S4 o, |9 v" k
  6. $in : in
    * C5 W4 A# ?8 G; b& y, E& a
  7. $nin: not in & L5 ]) a3 Y& V. R/ F$ L0 T% r
  8. $all: all
    $ l5 p9 M8 w7 }5 E
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
4 G. a, [( U0 `. B) q2 \0 V

8 r. A) S4 K  p+ e2 b3 ]查询 name <> "bruce" and age >= 18 的数据
: e0 f4 g3 q+ v8 N& i4 S9 ^
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
* T& y2 r; ]9 P, o: e( ]8 W

& d# `5 G! E0 {3 X9 q查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
" l3 w4 U5 r  P% n/ p
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

) ]+ B% Y7 V) u( _; l$ c+ o0 G# Y- s, s4 |. _9 B5 x
查询 age in (20,22,24,26) 的数据
; q; I( U8 `% E- \& I. G' {" D/ x
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

2 D$ K' O4 @; \# Y0 i
$ a' i3 e7 Z) r' k* w$ h查询 age取模10等于0 的数据
/ b, u$ Q3 p( a% S& F9 j
  1. db.users.find('this.age % 10 == 0');
复制代码
+ f5 F2 H( N7 X: w4 S6 b
或者
/ Q. y% T7 u3 r6 V. i
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

* k) j( |9 b0 }
& V: G% g0 ]) D- \1 P匹配所有
1 H& Y( y. o# ^8 N* M( l# H
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
- t' A# {! o& Q7 ~: c
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
- H) K/ u! F, s) M4 D可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
9 i2 W. Q0 y" I! G# C( [0 ^
) h4 l- \8 K$ w8 o# V* g. W0 F; x查询不匹配name=B*带头的记录
# I+ J$ c3 h# r2 ]  c3 D
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
- n& X$ C5 y8 L$ z
查询 age取模10不等于0 的数据 5 B* B, W6 x& i5 T; ?) a+ e
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

4 ?+ N- w/ u. f& P% H2 O2 X1 s+ z0 M' N6 O, ^
#返回部分字段 $ O. ?! x* Z, U7 X' u
选择返回age和_id字段(_id字段总是会被返回)
; T* k: h' G2 S0 w; [
  1. db.users.find({}, {age:1}); 4 T* `) l) g% X. p; T/ w
  2. db.users.find({}, {age:3}); 4 a+ _& F' k7 }- Q( S4 A9 p+ T
  3. db.users.find({}, {age:true});
    5 o$ w; g5 T& ^2 a6 c8 ^; j
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
! d8 i7 G; w: o  H! J6 }
0为false, 非0为true # \" m' C. G" W# f+ c0 z6 m
" a: ^& O# L9 l5 A
选择返回age、address和_id字段
- q$ u+ c" ^" O  V+ T- \
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
4 [! G+ W7 \: `# a4 r

! t5 [  L8 z% z$ v) J5 Z& K排除返回age、address和_id字段 ; V- P3 ~$ e1 i% t* G$ w+ X
  1. db.users.find({}, {age:0, address:false});
    & n7 C" n6 M$ Z
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
3 Z; m' u+ H4 u8 t
8 J) j5 D: I, T4 n. p6 p, q; r3 u8 j" {
数组元素个数判断 4 b' ^, ]$ U, c
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
0 S, ~7 d+ c" _, R匹配db.users.find({favorite_number: {$size: 3}});
, b7 D% d  x# i' E1 J不匹配db.users.find({favorite_number: {$size: 2}});
, g  m8 Z. e3 P0 [2 [* t+ q
' H1 h8 X- L# G9 C0 q: l# q) i1 D$exists判断字段是否存在
) G5 h! b- \  l( R# n, p查询所有存在name字段的记录
- Z8 K: ]5 g% ]! b) D- i0 N; Z
  1. db.users.find({name: {$exists: true}});
复制代码

  M9 o2 q5 C! [" W查询所有不存在phone字段的记录
, y+ u& n" b9 F7 O8 E
  1. db.users.find({phone: {$exists: false}});
复制代码

" t" @( Y! i  [$ h9 `
0 d9 ~) N; n3 H6 I9 {* V% H  ?$type判断字段类型 1 x# N& Q0 ?9 {8 I6 l! E+ g5 M
查询所有name字段是字符类型的 0 h2 d6 F0 v- f+ Q- h; J
  1. db.users.find({name: {$type: 2}}); : X- A8 u' v' a5 o9 b9 E6 V* R
复制代码
7 L4 l* S  k3 ]  ~
查询所有age字段是整型的 8 Z: R* b6 U6 P' Y0 d- G
  1. db.users.find({age: {$type: 16}});
    % L" u- ]0 ?6 i: y7 m& h  ?
复制代码

7 a7 d' V0 f+ @% H" {对于字符字段,可以使用正则表达式
  k$ [( H- C6 T- x查询以字母b或者B带头的所有记录 % Y4 F4 c; L8 o5 G- o9 V3 U5 i, ~
  1. db.users.find({name: /^b.*/i});
    & j5 n. s& T# V  k% `
复制代码

9 i2 i4 w( l+ \4 V/ l, g$elemMatch(1.3.1及以上版本)
: L1 q/ d& K8 P0 a+ S& H为数组的字段中匹配其中某个元素
" E1 ?- v; x2 a. U
: p# o2 F) h3 W  m2 }* a: cJavascript查询和$where查询 - J( C2 }8 G+ ^4 _, H
查询 age > 18 的记录,以下查询都一样 & g+ a; T2 z8 z
  1. db.users.find({age: {$gt: 18}});
    ; @/ b7 F0 ]8 H% ~0 J
  2. db.users.find({$where: "this.age > 18"}); 2 X+ G5 U- y, A8 x
  3. db.users.find("this.age > 18"); $ g  g8 g- J  v5 y
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码
6 i1 U6 S$ W! D
! x( y* H# }' h) i3 j4 ~% o
排序sort()
4 _2 r. k$ @2 _$ i以年龄升序asc
' O9 k% X4 |( p3 }8 Y6 r1 i3 ]% m
  1. db.users.find().sort({age: 1}); ! f' g. ?! `! l) P; m/ t  S, }
复制代码
) ?# U( e5 \( U; [
以年龄降序desc
* G5 e9 E& H9 @( s, |
  1. db.users.find().sort({age: -1});
    , Q  U6 D* q" x5 O! D0 u+ {- N
复制代码

0 {# o* k( w/ }9 o1 _; e( ~限制返回记录数量limit()
# Q9 `# M9 i! Z9 u6 S1 }返回5条记录 5 g' o$ Q0 J* Y& r0 b# [* k- c
  1. db.users.find().limit(5);
    - B4 {7 ?, X0 @. M$ c! _& T8 S* S
复制代码

6 F' s1 \. B3 ?6 e# j/ ^返回3条记录并打印信息
0 F3 J* A( S0 c; ~5 ]. u
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    & T. I- i/ L/ }* X0 ?( a+ _
复制代码
. u/ A, w3 S/ n/ N) J0 l& |* P
结果 ( {- x9 H! N1 O8 V( d
  1. my age is 18
    : H- h% a9 N7 {* ]) B4 H
  2. my age is 19 9 E' [1 U) j1 ]* r3 T2 e4 v
  3. my age is 20
复制代码

4 D! n& w0 x% _8 G! G& H' w
* c, O2 o- |; `( T" J9 _限制返回记录的开始点skip() 9 F4 |! Z; v7 U5 B0 K, T
从第3条记录开始,返回5条记录(limit 3, 5)
8 @: F+ A/ }- h+ g
  1. db.users.find().skip(3).limit(5);
    ) l" @. e" {) a9 `+ s
复制代码
/ u1 C' T0 o0 e4 i- g& b: E. t
查询记录条数count()
9 x* a2 d0 @$ [2 P2 Ndb.users.find().count();
3 l! ~" C$ V3 g7 X4 ]2 Fdb.users.find({age:18}).count(); & b8 |& H$ p  S1 M- [' d9 l
以下返回的不是5,而是user表中所有的记录数量 5 ~" k% L7 p3 m( J2 g3 _* ?
db.users.find().skip(10).limit(5).count();
' @% K7 ]+ K- C  L3 i如果要返回限制之后的记录数量,要使用count(true)或者count(非0) , t! E2 B" }' e+ j$ z! ?  m
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

' q  }- q) E# |' \. q8 @9 m
0 e0 L2 }9 q: B/ h6 b5 y5 W8 Z: J分组group() 5 f( Z" B, S+ n. w' j
假设test表只有以下一条数据 " M7 ^& Q# X: |  k/ }1 n
  1. { domain: "www.mongodb.org" 0 L) [+ l1 K2 K# O9 x
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} ; k. _, R# b2 m' a2 k
  3. , response_time: 0.05
    9 I9 R, g' J: C, r
  4. , http_action: "GET /display/DOCS/Aggregation"
    / w! F' Y# J) ^$ D( n
  5. }
复制代码

& w9 l9 \7 ~' K, N. q使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 0 t4 g" U6 G- w. w6 R0 \0 o" t: h
  1. db.test.group( / @0 o4 L1 y+ f' R" K* y
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} & F6 v( m6 U1 _4 l% ]
  3. , key: {http_action: true}
    ' U5 f) i% `1 [7 {  X) ^& W' \
  4. , initial: {count: 0, total_time:0} 3 y- ]' E- z% H6 q& l2 N
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } : m( n" D: ]9 H7 T* R9 s% @. m& ~! }' d8 q
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ; P# D2 j' Z5 \/ a
  7. } );
    ; G! d) c/ c0 Z

  8. 2 u* o' M' d6 `" d+ b4 o; ~& G
  9. [
    ) j1 b6 t4 ~. _  ~/ E
  10. {
    5 S- Q0 W/ G  _( H& y, n4 r4 {' c- R
  11. "http_action" : "GET /display/DOCS/Aggregation",
    - y# ^+ I. ]- h0 S- ?" X
  12. "count" : 1, & H9 J8 M, `: q; b) v5 X/ h2 a
  13. "total_time" : 0.05,
    8 o; E( \5 A. D
  14. "avg_time" : 0.05 0 ~. @' ^; T) ?. o; b
  15. } + E0 d( E2 \( J7 Q: R
  16. ]
复制代码

; n+ L/ p$ m1 m, L. D( B9 }5 O3 R. B; E" u" r# [0 W
$ C8 W# o, f# k) A1 H% k, D" c9 f
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
    $ X. ]) D$ d) A, }# i! Z
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
1 b# z4 I0 x  e5 ?2 }% m+ m
* F. ~6 N; P& F4 O3 h  s$ d9 x

6 N6 _+ z8 d& |) s; J" b
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    # |5 o' A: y0 b7 C
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
# }4 w/ [- ?: T, x: s
( A$ a+ g( a* O" ~0 X1 m
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

, Q3 \2 n" ^* f" ~6 f2 r/ g  l. B8 k* f/ K3 A4 q
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

$ M4 S1 y" l2 m% Z; C$ a0 [  x7 }- [$ r( D
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

# y. G- B% f# l0 |  p' K0 _  x' u+ z
8 P  Y; M. {- `- d$ p8 K) g
输出如:
  1.         
    / H$ g! _4 M- D# T+ B' u
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

) k) ?7 p$ s% ?2 }& M4 Z  |9 @. N$ e! x

* C/ R# M* B! k5 o8 B
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"5 e2 y: a! b; G/ J
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"7 d" k6 f! e4 J  O2 T
  3.        xmlns:context="http://www.springframework.org/schema/context"
    : D. K& u6 [4 t* j! M% |6 |0 ^5 @
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"8 |- l0 g1 P% w2 b( j+ O) ?, i
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans- H7 [7 \1 C7 J$ Y
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    3 `& O/ W) i1 [) I
  7.           http://www.springframework.org/schema/context
    ' b- S  q4 y9 \' y4 [5 k
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd5 K0 d( M, G4 ^2 O8 D
  9.           http://www.springframework.org/schema/data/mongo
    : i3 h8 S) s6 h4 B- _& y
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">; ]' b6 F! {, _- |, J+ l

  11. 2 n/ z4 ~* U; m6 q. k6 r
  12.     <context:property-placeholder location="classpath:mongo.properties" />. _$ i$ H0 H/ H+ [( ]* u( u, S
  13. , l* v2 x6 o, }" `1 d
  14.     <!-- Default bean name is 'mongo' -->6 i/ S1 t, C3 J9 _; V
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    - f0 d" S( O6 S8 n: `

  16. " D, q& b3 _! ?- W, \3 x5 o
  17.     <mongo:db-factory id="mongoDbFactory"
    2 c+ ~- @' i" \) W7 u
  18.                   mongo-ref="mongo"* P( S8 e  O- ]; U: c, j. \
  19.                   dbname="mongotest" />
    ( T8 ~* C* E3 |) \+ |+ D
  20. & e5 Y& i: C; {8 E; C
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">+ k- X8 M" h  P9 k9 I: R6 B
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ( d( ?4 Q6 @  d0 l3 X* ~$ e
  23.     </bean>4 ]9 g- j) M4 t% H5 U/ O
  24. </beans>
复制代码

; A. K  S( J0 D- V) x5 S

0 K& D9 i, U! C* E  @1 ~# E
maxmin的测试
  1. @Test/ D( c) F  v7 Y  [& R
  2.     public void testMaxAndMinAge() throws Exception {
      Z, n; f5 o+ y( ?5 E
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    9 u# \) }2 r7 x
  4.         Person result = mongoTemplate.findOne(q, Person.class);2 w& I& \) Z, m) I2 `  a
  5.         log.info(result);8 d+ I. s4 ?$ @) K6 ~# C& z/ q% q% O

  6. . H; ]: U  c* m/ Y0 B" N
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);: U  f% |( N2 l7 O) h$ |6 a. [
  8.         result = mongoTemplate.findOne(q, Person.class);
    2 D, W1 R" h; j. J! c& h4 E- d
  9.         log.info(result);
    ; h0 Q3 R, g$ s8 y; T& A
  10.     }
复制代码

* S" [# H5 N% O, [7 J& L$ I% D: |& h6 [  S
distinct的测试:
  1. @Test
    8 X+ ^7 q0 ^# F! p+ X6 U
  2.     public void testDistinct() throws Exception {& |* w9 b3 r8 o' B
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");& `$ B* w8 q/ X% i$ n2 l; y. h
  4.         for (Object o : result) {
    / `, _& O: i7 L) _
  5.             log.info(o);
    ) M4 R! |3 l6 j; j' f) S7 m
  6.         }
    $ U! m" K/ B" M7 s. d5 s- [$ d

  7. / ~) Y/ M; M( P
  8.         log.info("==================================================================");
    " W3 [/ c: U* y# W& J8 A
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    7 r  H, s$ X9 ?* J
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());: g7 X& `1 {2 ?- Q5 A; W
  11.         for (Object o : result) {% f$ K2 T4 V8 G1 N$ S1 `3 }
  12.             log.info(o);- u5 x; z, A$ r+ N
  13.         }
    % U% z/ d2 Q* u; r
  14. 8 [+ D0 c% ]9 }% b- z, d
  15.         log.info("==================================================================");+ H# S! k' K  y* a9 _  |
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    2 [% N  q9 j* s) j3 h, D
  17.         for (Object o : result) {
    % y- h3 E6 B, X' M) Q9 J% @
  18.             log.info(o);" W7 W! \) ]5 E6 A/ ?  j  \( B% V- g
  19.         }6 ~- A3 b3 P+ [# e! R% c
  20.     }
复制代码

9 }5 ^& o8 \  M* u! N9 U  T6 T: g" k  H# V
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    . f7 @1 N5 `' v4 y" M& W
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678. u& ]/ D3 _+ T% E  n5 J
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789# @' i: X* o$ G8 h
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    7 b& K6 C- O" t, h0 T
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    / k6 m0 l6 m* G( J" s6 q+ n; ]
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
      B% T8 I4 d- f- O! C1 {' C6 Z, M
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 1234567 ~- @& M$ `  y. f
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================; M( |6 o' k1 o5 Z& @
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 2345670 Z, t. Q) C1 ~& H# t  J
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    7 G% T# n# Q$ K( T2 C, `3 s' S: {
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    - r( Q/ n0 x7 ~- F+ s/ P
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    ! p* i1 e$ s1 i1 Z
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================! M; B- p& F6 ^* \5 i7 }
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa2 j# n2 i# W: L0 u
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb0 X4 k' M* c1 v, p
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc  C: h: \6 r' i6 |; o! a$ i
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www+ t) ], Y8 U$ l  R" U0 j
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx- |! k1 S6 }- U7 F* f1 {3 q
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy% \. O5 H4 V! p! A8 j4 i
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz7 T& e* F5 r: o* c3 B: I4 C/ U7 t
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    * z5 r' h, t- y# X) }
  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 K: D3 @, b6 ]( K( S( B9 {
* u6 B9 C  `# e4 C5 I% Q8 i
这里我要特别说明一下, 当使用了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等信息。
% X. C6 G7 E" n

* T7 X6 J+ m/ U3 f
0 e- j% s' _- \2 I4 c! ]
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-3 17:37 , Processed in 0.174688 second(s), 23 queries .

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