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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:# o4 {! b/ v- R% k( e3 J* `
2 l7 l2 p) t7 F  F5 X
1 ) . 大于,小于,大于或等于,小于或等于3 E" P+ N1 l0 }% b3 ^$ g! C8 n

* x" }/ O# D7 q" Q2 u. ]2 Y$gt:大于
& A, n8 Z! S5 u5 {0 }# [$ h7 ]7 Y) a8 J$lt:小于
) d5 {" n8 {  G: G. W/ g$gte:大于或等于
" a  S- H) [# x$lte:小于或等于: \0 J" I: I/ l9 O7 \
0 D& L9 a9 H1 ?9 n
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    ! t7 E5 \! C9 X+ c3 m
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value0 F& M& ^1 b- w0 |6 R
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    1 f/ C6 V! v" J& h
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

7 z/ M3 n0 |7 N" b/ O
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    ' ?5 {# E- {3 \8 p1 l# N- m- h% t9 F7 g
  2. db.things.find({j : {$gte: 4}});
复制代码

+ [$ y+ b0 u& V" m7 Y# G% I7 x
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

) e8 F# s( B0 Y6 X  O0 G5 m4 m, i% K
% r+ R/ h; z# v. I
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
! z8 ~6 t# t. |, V3 i; ^! t
3) in 和 not in ($in $nin)
2 Y* y6 i  V6 `0 E# u: a, P9 E; L% \& F- I- H3 d
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
+ R9 V3 ^) N( J, o8 _' S
例子:
  1. db.things.find({j:{$in: [2,4,6]}});* i* V+ M% k2 A- n5 d7 ?
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

8 i, n7 a/ l- s* D9 N7 r# ~* Y8 d8 J

( ~/ C5 X* q, e5 `4) 取模运算$mod
& [5 P! c0 `, u6 S6 D, n
3 _3 j* ]* M( W& \0 {! i2 E如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

; r& A6 ^3 c! I" @
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
' X  a3 u* A! I

+ ]3 Q5 A* j: v* Q# I8 u5)  $all
, `' C% [7 ?2 C6 B6 c. e9 s, D4 i4 M# ?& O( n! H2 A% G( X6 c
$all和$in类似,但是他需要匹配条件内所有的值:
# C% {3 w$ d% Y) v% H: M
, K' L6 R& {9 Z2 u$ \* n( ]' \* \如有一个对象:
; |/ P* O9 v$ Z( j: V; z
  1. { a: [ 1, 2, 3 ] }
复制代码
: f) o8 f) q% Z4 u
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
  m2 Q! }1 a/ R
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
* I5 F% R& a, W4 I  M# s) ]9 j. \

$ r: ~, ?$ c, S  w6)  $size
" l" J8 b' Y1 W/ c4 _8 i
0 ^- M! W4 M. G2 O! W$ P$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:4 h- o. I4 \+ C; Y+ _0 }9 h

2 D( a+ @$ j$ j* ]/ l3 y+ h下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
0 j0 t) V" q8 u. M
官网上说不能用来匹配一个范围内的元素,如果想找$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.

# P9 n4 a7 h# t  N
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回: j6 c2 }6 K* _0 v! w1 a* j
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

+ Q2 P. ^6 W& Q9 {9 p. I
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    4 y: P! ?0 E& |6 W
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
1 Y- q% b. F( y
9)正则表达式
0 U3 u# ]3 m6 {& w6 h. u$ {' }2 B, e! |4 K4 t, Z
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

3 ?5 c5 i5 ^+ M- D! I6 F3 U5 x8 j5 z
10)  查询数据内的值& ]1 d) x" N$ s  v5 T

- k8 }4 ]* B5 e2 Z下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
2 F/ d! L5 X# m6 x4 D& X
11) $elemMatch9 ~3 B0 D2 I; H# e5 O
" a- \8 w7 ?: q+ \7 ?
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    , K# p: c& `! a! V3 z( a, s
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    $ w, w( Y" X( k2 J
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    % k5 u1 |1 `+ {" Q, Z7 [
  4. }
复制代码
3 L4 p+ k5 x" o" B) p
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
1 G; N! B7 X$ a" B* L5 M# I
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
/ R& j- u: u- t  R  V$ C* a% Z/ `  u& K6 c/ {: c' m* w
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
" V) s, W( x; U5 J! @: Z( G- W: h  d
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
; j/ ]" K* R# ]0 U
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
2 S  n: j" N6 M; p+ {
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

7 C5 `" P( Q0 i9 E% e
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

3 P5 y# z/ w- c" D
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

* N+ B- U  {: w) N* q
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    9 z8 x" A7 L7 ^0 S0 I$ I3 }
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
' X  _! R0 @* D: h2 `% ~/ ?9 A
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
. S( Y' T6 a( E  M4 E$ s- r3 R! k: c# z* S3 x+ I
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
6 K0 a. Q9 m6 [* r0 D# \6 Q$ \5 Q5 H9 y  j4 G
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
" k# F9 r6 S4 I' ?* w2 |  z; q" r* o* g3 b
版本二:
8 z4 u* y  ^) x9 v" {
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

* Y4 M3 D! Z+ U2 V7 w. ~* L
  1. use admin
复制代码
3 h; K+ n. }' u0 i0 m( x0 H# Z
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
% e2 x5 P+ X/ P2 b7 I9 B$ W* w
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
6 M$ @1 ~  @( X- r$ Y6 V
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

5 ^- q" @: s" p, v: k+ @5 K1 W1 Y
         5. #删除用户
  1.           db.removeUser('name')
复制代码

9 }! n7 @3 o( F8 x
         6. #查看所有用户
  1.           show users
复制代码
4 f1 F& Y" @; o* \! J  w. ~1 \
         7. #查看所有数据库
  1.           show dbs
复制代码

: Y1 ?( H$ V% k2 D# a' J
         8. #查看所有的collection
  1.           show collections
复制代码
; y  B5 F6 S+ \8 J6 ~/ ?- n& m5 `
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

, T1 h0 J# [, d1 ~  \
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
) B0 C2 q  o7 Y
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
5 U- C- w! R0 H+ n% X
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

: y! L4 K2 x" e9 \5 Q; P
        13. #查看profiling
  1.           show profile
复制代码

* ~" N4 ]. s( S+ \8 G- I
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

; m& f9 Q+ F2 E9 X7 o  d8 d9 P
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
5 i: }0 Z0 r8 G
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
$ K* ]! d8 e' w# D5 y4 [6 b
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

' h' L; ^. \* q1 S
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
& e( c  {; j" U, }
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
3 r3 k, b' U/ u9 S+ |4 F  A% P& B
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
* N7 J9 s( [3 o8 g1 h5 b
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
/ b6 g) `( v( d0 x& e$ }
   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()

% P: y3 U3 Z+ R2 t8 \1 R% l2 a
6.  高级查询
条件操作符
1 \, m' }0 ]7 ?4 n
  1. $gt : >
    1 O8 {% ?  ]5 Q+ ?/ t: j
  2. $lt : <
    6 Y) R; W* W) H* D
  3. $gte: >=   B) p5 g4 H4 R
  4. $lte: <= 8 U6 D  f1 e0 G+ C6 P/ t  J
  5. $ne : !=、<> . b& I3 n' F" T% W: e. q
  6. $in : in
    4 f, A( w  J! Y% s3 x+ r
  7. $nin: not in
    ) u  V, l. E, n. X. E2 l1 Z
  8. $all: all 5 F1 d" n! r6 F9 \  i
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
4 s4 J% _; R6 ?& X* o
) N) V# d, f  g5 s" A9 f; E2 g
查询 name <> "bruce" and age >= 18 的数据 ! e- k" c- V! ]! h+ ^- N: G
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

3 e! t2 r) T+ S4 B% j
, m' t8 s5 X- h: Q8 _查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
3 e; O0 T4 k. c( H1 v5 y* P% V
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
" M* }! j3 U; l/ D: O
4 m( n- h0 o% I: }- r
查询 age in (20,22,24,26) 的数据 5 \$ a# L8 I: d; L5 C' \% B
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

) `) B+ ?# v( Z- H& x& \7 q: I# I/ r* d
查询 age取模10等于0 的数据
2 o! r* w* Y/ N: e( K
  1. db.users.find('this.age % 10 == 0');
复制代码

# ~' E- W, T' e6 v) J或者 ( G% k, V7 F0 e7 T6 S  S8 x
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

1 U+ F# W/ c0 d9 @! G7 J
# }4 L6 Y! l' a9 w0 c* {' i! \匹配所有
" B" N, l5 e3 q7 Y( c* Z# ^
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

& Y2 b' \& @; l, X可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
- Q/ \$ m" z% X( @可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } ' p3 `0 i" H* x( l

' Z5 ]. Q' O* g4 j1 e, ~8 C9 i$ v查询不匹配name=B*带头的记录 # [. R$ j$ i$ h# F+ x+ k
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

+ t& w0 U% b1 V- I5 e0 w8 l查询 age取模10不等于0 的数据
) n& Q9 y7 p- H+ P1 x9 q
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
0 G8 _% Z+ C: U! t3 P+ H

; M$ j0 V: ~3 V4 }#返回部分字段 ; L. C* R8 l" W
选择返回age和_id字段(_id字段总是会被返回)
; x9 ^/ ^- A  f0 m0 L$ [- _6 s! Z
  1. db.users.find({}, {age:1}); 7 a  h! l. c# H
  2. db.users.find({}, {age:3});
    $ }3 v$ b3 o5 M  J& \
  3. db.users.find({}, {age:true}); % m9 W" x; _( w
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

- r) x8 S+ j4 h" S3 d0为false, 非0为true 0 ^" o! `9 g% w
" K- Y7 Y6 x: q5 q- K+ D
选择返回age、address和_id字段
  X5 V; L6 l3 I5 U
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
& f# [1 k6 K, s% s5 `

9 K/ E- o8 h! y: ~6 B' d, k6 ^排除返回age、address和_id字段
& q7 ?* d% _5 K6 S# x6 Z! ~9 D
  1. db.users.find({}, {age:0, address:false});
    , A: X& r, t$ d9 M
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

5 [( e5 ]! A& q9 b- b) F2 d; f# C% p# |8 n6 P
数组元素个数判断 % w- u& A6 f' F' `/ I5 Q
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
; J# }5 g" A  f; c) F* y/ [匹配db.users.find({favorite_number: {$size: 3}}); ! o3 T0 _( @' m5 @2 u
不匹配db.users.find({favorite_number: {$size: 2}}); * i, v" U7 j& V9 X
& I( s* Z+ B6 x- Z
$exists判断字段是否存在
, K" C+ y8 j  Z6 {8 C3 Z% l查询所有存在name字段的记录 ' N& S0 V! V& X0 j7 B, M
  1. db.users.find({name: {$exists: true}});
复制代码
2 _# x8 ?4 s4 g7 n& S# g0 O
查询所有不存在phone字段的记录 & j$ _) O1 X2 r1 S1 h& G8 e: Z
  1. db.users.find({phone: {$exists: false}});
复制代码

/ w, o( Q. Q) H
4 i% W" k; P8 _3 N# @$type判断字段类型
8 |; G# L: e/ Q查询所有name字段是字符类型的 , I- T; ]7 D; D2 l7 g! y$ l
  1. db.users.find({name: {$type: 2}}); # D! u/ M9 r0 p' ]9 }) `
复制代码
6 C" }9 g! J5 p: {5 X0 i
查询所有age字段是整型的 ' G7 k) Q: x& M$ \" o
  1. db.users.find({age: {$type: 16}}); , x) X4 U. A5 P' h8 g( A
复制代码
5 F8 e" F0 U0 |: p2 |
对于字符字段,可以使用正则表达式 3 D& B, c+ M5 ~8 U9 x) q
查询以字母b或者B带头的所有记录 , w: a* K9 d( P
  1. db.users.find({name: /^b.*/i});
    7 _1 m+ Q  z- y/ n9 \( c* q3 r. `
复制代码

& {2 m* Y* p- \& l& K' _$elemMatch(1.3.1及以上版本) , j7 @! Y- m% q! @
为数组的字段中匹配其中某个元素 / m( v3 N- s0 G5 i' j3 ]" o2 E* [
& [. L, Y/ K% Z. q: @2 H
Javascript查询和$where查询 6 i2 O' F9 d! A1 u* f3 ^# a
查询 age > 18 的记录,以下查询都一样
. I4 e7 T. p; q) E
  1. db.users.find({age: {$gt: 18}}); 6 g. d9 c0 E% O( I! k; j+ d5 c6 J+ m( m% ~
  2. db.users.find({$where: "this.age > 18"});
    : I* _8 ^. X, m9 H# G7 O+ `+ _6 K; S* F
  3. db.users.find("this.age > 18"); 3 a2 Z9 V8 K5 ?) ^4 e
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

* o* L3 m; W6 {# X1 X. D) o8 a( r# z1 m/ H8 E
排序sort() 9 k$ R" b0 K, p+ P* F+ ]
以年龄升序asc 1 J. e+ G- h  V/ H- H0 U
  1. db.users.find().sort({age: 1}); + M* a1 g8 ~. a8 Z' z+ b8 k1 }
复制代码
, O0 X9 Z/ _9 D. \. a' k7 U
以年龄降序desc
, q' a* I+ g& c" N! z, }
  1. db.users.find().sort({age: -1}); 8 _/ {# Q4 n! ]! }. K
复制代码
1 ~% ~4 y9 i7 G6 Z: `" ]" z
限制返回记录数量limit() # A- _: O  [/ ?3 J1 y7 S& K
返回5条记录 1 {. y- u$ c0 ]: I7 q+ b
  1. db.users.find().limit(5);
    ) P4 ~; E' Q3 L8 z% ]
复制代码

' ^7 p) Z0 K% [; K( E0 ]返回3条记录并打印信息
) Z* [/ w+ U- r& q- E
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    0 \% D5 b& T8 G0 P
复制代码

; g& J7 H6 W0 O5 X2 i6 o, Q结果
; |0 K* y$ ?4 e
  1. my age is 18 2 y) W0 ]( r4 P& d  G7 d
  2. my age is 19 0 y' ^3 X- @/ Y, R
  3. my age is 20
复制代码
1 H2 D4 w: o8 F+ b! n4 J3 Z/ a

) L; N0 m2 P8 z( ?1 ~限制返回记录的开始点skip()
$ ]! V1 k+ _& d7 R7 K& t从第3条记录开始,返回5条记录(limit 3, 5)
* Z/ q+ d9 y* R% b/ G9 y8 n% T
  1. db.users.find().skip(3).limit(5);
    1 W( w- m; G) n" |' J
复制代码
) D& A2 w  |5 j1 D' ^( ?
查询记录条数count() 5 O3 A# d0 t& m% y0 C
db.users.find().count(); 4 R" E1 c& @) u3 n2 Q+ V5 N
db.users.find({age:18}).count(); 5 R0 h1 t" C) J5 x
以下返回的不是5,而是user表中所有的记录数量
8 L  b( ~+ Q6 A* `( Q+ F: M+ |db.users.find().skip(10).limit(5).count();
$ T4 |  }- `6 w. q9 [如果要返回限制之后的记录数量,要使用count(true)或者count(非0) # X2 i+ e; o8 ^+ ]! z
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

. M; u% }- N- e% Y% h2 a$ e; ]6 |, t+ A" _! r! l7 I7 N
分组group()
- N* A8 E; ?' t假设test表只有以下一条数据 1 I: R7 a! z0 I: |; E
  1. { domain: "www.mongodb.org"
    3 i0 W/ H/ J9 A. a/ S2 F
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} , H* X* J9 e0 z
  3. , response_time: 0.05 3 E$ p- S" B( l% z3 P; ?" n
  4. , http_action: "GET /display/DOCS/Aggregation" / b# h# W: t, r5 V1 g$ s; `5 k
  5. }
复制代码

; m; L7 L# O, D, r使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
. Z6 ]% ^# _+ L; G8 o
  1. db.test.group( 1 t) I' _: ]+ J4 ^
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} 7 S6 V  B4 j1 @% C) o0 ~6 h' E8 l1 \
  3. , key: {http_action: true} ! G+ y- |& C; s& l9 G' T0 g/ P8 o/ X" K
  4. , initial: {count: 0, total_time:0} : h+ x5 d- O2 S$ }# x5 Z1 [
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    / ~: h. ?" y9 Q6 b, ]0 e
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    5 V0 v8 t/ c: ]( y# S" f5 t. D
  7. } ); ; F- e( c; A8 }) a) u

  8. , g! @& U4 [9 D6 H3 O: p
  9. [
    . m9 y* G6 }8 X! X, f4 t) a, S  h* N
  10. {
    + s2 ]& D+ N0 ]4 k# v- \7 ^2 h& R
  11. "http_action" : "GET /display/DOCS/Aggregation",
    . c3 p8 `5 j0 n# a; z- q
  12. "count" : 1,
    ' `7 I  P! J4 u+ [
  13. "total_time" : 0.05,
    1 x. _1 B+ I' Y1 c4 L
  14. "avg_time" : 0.05
    # E/ V, N" z) l. {8 H9 T) F% M
  15. }
    4 F7 ?& n4 m6 {# y# s8 U
  16. ]
复制代码
+ E' v0 p- F" X. v1 o
& e0 f! U6 a& W& |3 M$ B( k6 ]6 h0 s
. J. E) j8 ^9 L/ G7 a
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" O, X; A& z0 q
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
" V, k0 t% Y4 U& ~, `

& S) a, G* \% l: K

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

+ G* c& d2 Q: K; ~
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
" e8 q; [7 R; @% ~0 P2 O+ ~7 t! S
2 n: \( e/ O$ W( [! p
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

2 r7 m  _; b# p1 U4 h7 U( L* n7 f
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

0 h2 [1 n+ S1 N% G% y  a
5 L* v0 O1 ^3 |" y9 j+ T5 N$ v. D
输出如:
  1.         , B7 n, Y1 V2 n+ k% C! q! y/ T
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

- S2 _) A0 K+ p$ _' p
4 t- i9 u& b$ K6 E- z& B6 U! d  x
* L2 J; w/ ?1 Q. w
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"% q; D( I% U+ `8 ~
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    ' d" J& V( y1 A
  3.        xmlns:context="http://www.springframework.org/schema/context"
    3 c7 U$ D! T1 U* D2 M# ~. y
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo". \' d, k& Z3 I! g% N# R9 W$ Q
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    % I7 M0 l  d7 l- X5 L5 ]5 c
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd6 R/ Y; R: ?6 R# ^& w
  7.           http://www.springframework.org/schema/context
    ! N, B' o3 |; l/ V
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    $ K+ \, q' J; b( p( A
  9.           http://www.springframework.org/schema/data/mongo
    & P! A5 s$ t3 h$ o
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    ( e( ~7 o* ^* g& L; q; U; Y8 l
  11. 1 n. I9 k6 r/ H! }" p+ H; T' Y+ y
  12.     <context:property-placeholder location="classpath:mongo.properties" />$ l$ j! g3 U( [# q8 y' n! n
  13. , D1 l4 ]+ {, ^0 v
  14.     <!-- Default bean name is 'mongo' -->4 G, c1 c6 o: @( n4 z9 C4 Y
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    , D+ P2 n$ I1 T/ c6 k/ l2 g
  16. ; z7 j+ I6 l; j- z6 E) i
  17.     <mongo:db-factory id="mongoDbFactory"5 |$ S5 W4 g' I5 g: E
  18.                   mongo-ref="mongo"
    ( K; K# a8 f  F
  19.                   dbname="mongotest" />! s/ j9 v8 K6 H4 S" L

  20. / b/ J- |( E. [) h$ a
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">  {* Q, j" V2 ^1 B
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ( I  y9 G' d1 j2 k4 ?' A$ f
  23.     </bean>( H& }- @" b( Q) l# V; D1 }
  24. </beans>
复制代码

" _9 P+ `& g2 r$ ], Q7 W
! u( Y) f" @3 [7 f. q7 F+ f6 P# {
maxmin的测试
  1. @Test
    4 }7 s7 V% {2 _/ k9 R, E/ ~
  2.     public void testMaxAndMinAge() throws Exception {- ^- ?4 Q7 V  C: b$ n1 J
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);8 F  g- [. M  Z, T5 F  m- y7 T4 W% ]& O
  4.         Person result = mongoTemplate.findOne(q, Person.class);9 J; @. ?5 V) Z' E/ g6 d% w
  5.         log.info(result);: U# g+ r1 |; ?1 z; _
  6.   p0 h6 R( S2 U' y$ x$ W; c" d- N1 p
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    & h4 K  ]- h2 r
  8.         result = mongoTemplate.findOne(q, Person.class);
    . j* Z+ Q# d( o, c# F
  9.         log.info(result);* H- N. ]( l7 r0 ~! Q0 z5 T2 M4 _( z
  10.     }
复制代码
' v' _5 K, r( A2 J+ V

' G- \8 k+ r9 U8 _" z
distinct的测试:
  1. @Test1 h) z3 S. U8 w$ k( U6 |
  2.     public void testDistinct() throws Exception {' k$ S+ z' M) c1 B; X
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    2 F$ i+ J7 _& p$ {. w
  4.         for (Object o : result) {$ T- z+ J( y, }
  5.             log.info(o);
    1 o+ ~+ k5 B/ l! \6 M/ s) |
  6.         }  T& x5 B' ~9 a0 |. ?
  7. , s' d9 O! I9 k9 A2 \0 u; }2 Q8 f
  8.         log.info("==================================================================");
    8 Q3 V# p7 y7 |1 s
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));4 ?3 F) Q5 U; B
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());2 W* O9 n9 ]3 [
  11.         for (Object o : result) {2 I% ~+ N" C7 s- b
  12.             log.info(o);
    + @& i7 b: H' E% Y, V; Y! H; x
  13.         }- W( p0 K/ v+ h0 c( X. m0 G4 v- J
  14. " e& v- n. a# C) y. M7 {
  15.         log.info("==================================================================");: h5 I8 p2 ^. x. n9 I
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    " M( U6 L/ [# @, c0 U
  17.         for (Object o : result) {: Z- S: g& E- Z2 V; U/ G& X9 b5 z
  18.             log.info(o);
    & i4 J, V/ s! J
  19.         }5 E. |, M) w/ j; J* X, L) r
  20.     }
复制代码

7 l) ^% w6 s7 ~9 s7 z  V# K
5 p2 N% Q+ m! t9 ?
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    " A& B4 g0 ~$ D/ p* m
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    / O; x7 d7 K; l" K1 a
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    : s- p2 ~5 {; P0 Q" N
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654% t# Z' J0 E! b  W
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    # f) y1 ]; c5 M& l7 Q
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo: s% k# }' h1 x, ]- E3 l
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456. P# a7 U( ?2 J2 \7 M
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    ; `0 Z. G/ o, }' M
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567! z: Q6 [- |; A  y
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678! P$ H0 |1 k7 p; {3 V
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789. z" b$ P% C. A; I" ]2 ?  y$ i+ \
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876543 w! v. N" P: }9 A/ T
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    & I% o' z" T; ~* N% t; }  M$ I
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    + c3 f* l' D. i3 C
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb2 W; R6 Q9 |2 F; c% L3 K9 a8 k. M
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc+ d! i* U% f# q
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www# F- z& ?. |  v2 Z5 G5 w; R+ s
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx: O; C  h" Q. R$ j9 g4 K
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy5 j* v' o( p- R! v0 r. ?' d8 O5 y
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    8 ^, X9 Y5 J* m- ]9 t- A
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    / {' S8 ?2 x) w4 Q
  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
复制代码
& y9 W: X, y, I  F! O

9 T, j' x% w9 ?8 g! ]0 ^; T, 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等信息。
- i5 }* n7 c8 y% Z$ |: X( x) A

3 K6 y9 Q% f* t7 Y" i2 \: A
, V* Y5 E4 W4 {" B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-16 17:20 , Processed in 0.089465 second(s), 23 queries .

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