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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
版本一:
; d# P4 Y8 }- `* Y4 u' \7 M0 z* P6 L) D! U# }9 v6 l
1 ) . 大于,小于,大于或等于,小于或等于" x7 T9 y8 S. p. L" Y- c& ~2 ^( l
6 X* \2 f! ]* e+ H9 O5 m3 v
$gt:大于7 T/ t" w* A( G7 j
$lt:小于( i3 z, ~1 G0 Z$ n& U2 Q& v: ^9 J
$gte:大于或等于
: t& J8 N5 I5 L1 v$lte:小于或等于
7 Z& l! B9 M' c, c* w% c3 r( x) O9 O( _2 V1 s$ b% g: }
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    8 O+ m5 w+ x6 j5 E9 l! J0 r# |
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value5 W7 ]1 _8 [) f, ^0 ~
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    0 ~8 g+ @) {4 _7 Q
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
0 |1 H: E& _3 _$ p0 }8 C
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});, V  C# X# X/ C
  2. db.things.find({j : {$gte: 4}});
复制代码
" ?: F  [' c! a) R1 }! Y
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
! ]  f+ s$ |( K* P: ?  r3 t

) D5 E% Q/ q1 ^7 v3 |( s9 e8 Y- e3 m6 `2 k9 q. I( j
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
2 |0 G0 D- |8 V3 x: V7 L
3) in 和 not in ($in $nin). D* y. ?6 a4 `

: x+ ^2 V! t+ R/ a+ L3 y5 S- i语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
0 j, ^( {$ C0 \: _2 r: A7 `
例子:
  1. db.things.find({j:{$in: [2,4,6]}});6 H: o1 S! U, Y! ^0 {* ]/ l
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
: J: s, a9 u, ^4 M

( ^! U; H/ [  P5 \7 @4) 取模运算$mod2 q/ W, ]" h" n* W* U

; Q2 {1 N' U4 s' e; t如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

! }) p1 ?5 \3 J! n
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

# _# R+ g; j1 H0 [, @' k

& S* X2 w0 `; T! n% A- b5)  $all- I! b- a  z* V
! V( ]( M  v# |; q; a9 y: ]
$all和$in类似,但是他需要匹配条件内所有的值:) V! Y+ J1 f" }) [

' w5 d. \; X; j) N! A2 {如有一个对象:
- }0 j! K5 K+ ~) k$ X3 W6 U: G
  1. { a: [ 1, 2, 3 ] }
复制代码
1 `5 x8 u1 a! H7 }+ V( N8 K, ?! ~
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
2 z) [/ O6 u+ ?6 S" Z1 _% P
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
& r- H1 @+ `  U# S

% e! F& f7 Y1 i" }% U6 X6)  $size
/ u2 y' Y, K+ R1 l3 M) N& @  b$ J. Z
3 Q0 C3 V- }# j$ l- |1 g/ S$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
2 t& c7 `0 s% |% b: j% Z- D
3 W3 V. h3 w9 g. f2 F& a- g* ~7 Q, z3 P下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
" [7 V3 C3 d  E8 C
官网上说不能用来匹配一个范围内的元素,如果想找$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.

# B; f) _8 Z8 ~; z6 T
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回0 D1 P8 J% ~* u, `6 F
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

9 W* e" c. _- O( T; T
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string- c. ?/ \/ B& j- `
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
( Y% L( P4 B0 a2 v9 `. H$ z/ j* z
9)正则表达式
' U" O8 w: q1 a: E3 Y4 W/ ^
9 l3 H/ r: c2 i9 T5 Smongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

4 h: ?3 a; O& B  M' ]0 c  f
10)  查询数据内的值
, D! k1 `8 X7 `; D
: {0 X$ b# J" o( l/ s8 `- r: U下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

; b: O; H, a4 T2 O6 V
11) $elemMatch+ |7 c, h, W* u$ [- o
4 K& `( V. W0 w( u
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 2 \7 ]( z# a+ P6 \( x! V! ]. ?
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),    N" M. h% ^7 t7 ^; B# k5 a3 n
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    / R. o- b' r3 A* `' ^. ?  y
  4. }
复制代码
0 W) Y# J% a# F. a- B
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
/ x" g& b6 U* n$ U% Q9 S# m
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
0 y/ n& x6 ^  w* W" Y/ n, _0 |) x8 U1 D8 n
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

0 a9 ~8 W( d$ y% r3 W! R0 w
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
% K: X3 ^9 d# v
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
- c) ~6 ^0 U& s/ I
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
$ P. K" i4 A: R8 E
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
9 y8 `. H" y$ U! q  s; _$ g* d- V
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
' y6 p; f3 q* |5 J
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );6 _! X' ~' `! A% {9 ]9 v
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

8 Y& t8 f' P/ N: }% ~
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
- W- f$ R4 y% E# q% B$ |, z# Y
+ p' ^. b! v4 ?# R0 y& C$ _mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:, A2 {6 {% O. n2 t7 t) ?. F1 ~
5 {. d& [& `6 X  o
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions7 r) L  S6 h! t7 I

( B3 y" x, z9 S! S1 [2 K0 J2 F/ O版本二:
" k5 \/ G! A+ X( n- I
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

6 t" j( j, O% f: |' A
  1. use admin
复制代码

" D# S6 B7 a# f7 K+ _6 s. v8 I1 t
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
6 u# x% W5 Y/ r
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

- U, [3 C. ]; C  j6 `! k
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

+ ~, i* D5 A" `. J7 k
         5. #删除用户
  1.           db.removeUser('name')
复制代码
: Z; T) @: z# `3 W2 {2 ?+ V
         6. #查看所有用户
  1.           show users
复制代码
5 ~; f2 J# T3 V+ Q) J" B
         7. #查看所有数据库
  1.           show dbs
复制代码
- U2 v7 D4 ^2 M. X! ]
         8. #查看所有的collection
  1.           show collections
复制代码

- T' o% [  K- N$ h: X. G' ^; w
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
0 ^+ }! Y" V, ?
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

' @( `6 `" o0 i' G. L: T2 _
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
0 P4 w' b, p! f  V# {
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
  d$ q) B4 q9 Z) Q- ]* Y2 O' Z
        13. #查看profiling
  1.           show profile
复制代码

& j  o! e' R6 Z1 H6 ~8 o
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

3 Q& |1 F6 c  y2 c5 T  N: w5 s0 H: Z
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
" v% c2 C+ f. Q7 _2 \' R
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

5 A" q: l% ~! s4 |
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

. Q2 _4 W8 @/ _  F, ]
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
8 V9 L8 u; ^& e# R
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
" T3 S' O+ Q( q& t
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

7 `- z; b5 i, c* G6 c( v
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

% L3 ?  v$ ]) w* V% W
   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()
- w! S$ l7 `& D0 E( u! w
6.  高级查询
条件操作符 " c5 E9 H; T2 Y3 R( G* }" }4 T
  1. $gt : > 8 m& T& ^0 R  G# \
  2. $lt : <
    : }' ~6 R5 Y$ F* f& Q6 C  {9 ?
  3. $gte: >=
    ( P% o, k! m. X% K
  4. $lte: <=
    4 ~- @2 V/ ^. k0 v3 U$ i! x% m" y
  5. $ne : !=、<> ( s# ], x4 ^" K/ r+ w
  6. $in : in ' E5 b' ~- T. p+ ~7 [
  7. $nin: not in 3 }1 }5 f" A: u9 d4 p- v' W/ N
  8. $all: all : W4 [- y2 R" E1 U2 k
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

5 D$ N) j9 O& |. c& ?  _
' K3 {( j2 j1 k2 i" {& D查询 name <> "bruce" and age >= 18 的数据 ' E8 p8 I  u& m+ f9 z
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

$ L* Y$ t3 M% p6 k2 v  M1 j. G& Z, F7 W2 P6 {
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
+ e/ O4 K+ V0 h
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

7 W7 y- r$ u9 h- u* R1 ]8 b: j3 A, W: ]; g" S( R( b
查询 age in (20,22,24,26) 的数据
# ^* }* X% Z0 u0 Y+ }  s
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

: P! V& o  c6 o0 X) f' J
& a6 p) P5 E( c; w$ |; O7 y查询 age取模10等于0 的数据
/ w# g2 f) _( r# ?
  1. db.users.find('this.age % 10 == 0');
复制代码
3 O  X* Q' t3 p, z
或者 - U/ E% M3 D* J4 e, u- F9 l/ L% E
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

+ e& y) H/ `! B$ P. A& ]3 D  e& |5 i  X
匹配所有
$ i* {# r! N) k7 u0 U# p. B6 e8 h
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
6 {, C% D. J* T
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
/ s* a% q- t# m0 N1 f/ c1 F& v7 D/ p可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
* `  [9 E. S- p7 `, y# {$ `, {4 c) F& Q( [8 w* N* H
查询不匹配name=B*带头的记录
0 i/ L: [& s" G+ N, u
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
9 |7 y+ ~4 B4 g) w4 l
查询 age取模10不等于0 的数据
6 T. l/ F$ f* K3 M! P2 G
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
$ C( x$ j9 |& ?
. _  @% R" J6 I; ?7 r7 D, e
#返回部分字段
8 Y. k2 y( ^& }6 c) i选择返回age和_id字段(_id字段总是会被返回) 8 ^: x7 M4 g; k& o" J# X) j
  1. db.users.find({}, {age:1});
    9 l7 x: s- O. _/ v+ f* \
  2. db.users.find({}, {age:3});
    8 u1 h* Z6 z; S+ g& A' b
  3. db.users.find({}, {age:true});
    ' Q8 B8 B9 w0 w0 i8 u  E0 Q+ ?; K
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

4 h# D  U5 d/ w+ C9 F  Q) Q; V0为false, 非0为true
5 n. v5 O6 A& x0 U/ X; p0 D) [1 ]0 Y- V: b$ k
选择返回age、address和_id字段 ) Y+ M7 q0 k9 T
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
+ {9 m6 g1 {) e' S8 U
% e8 V* \$ D1 y: x  _! X9 E
排除返回age、address和_id字段 ! D3 b' w$ ?5 I6 {
  1. db.users.find({}, {age:0, address:false});
    + T8 S' v/ @+ f, c/ j( c7 m
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
$ ^6 k4 L. [" i1 R1 [9 j5 k
' v8 n, M- ?5 p9 F
数组元素个数判断
3 d4 m0 d4 h1 p# s. d( V对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
1 O: I/ X0 Z5 x) @匹配db.users.find({favorite_number: {$size: 3}}); 2 F) x( x3 W6 Q0 h4 B9 @, Q. `( o
不匹配db.users.find({favorite_number: {$size: 2}}); - ^2 y1 ~1 T, l: `3 T: w) ?; q

9 n9 w. B9 ^2 ~5 u, c% ]& H$exists判断字段是否存在 / y1 E/ w6 \; U+ N
查询所有存在name字段的记录
1 Z) d5 f: P; S& v# \
  1. db.users.find({name: {$exists: true}});
复制代码
! M* l, n. A  `- y- T  o4 y
查询所有不存在phone字段的记录
" y4 P  B6 I7 l# G  A( B1 m
  1. db.users.find({phone: {$exists: false}});
复制代码
: i; Z" J5 [0 H- b  i& U
/ N* G) l3 f2 H+ f; o/ }
$type判断字段类型 0 g+ L" B1 O& a8 }" [
查询所有name字段是字符类型的
  j, o( `9 X+ D1 x0 M
  1. db.users.find({name: {$type: 2}});
    & Y! ]6 w' H' A
复制代码

( J  x" i1 q! g; ?' Z查询所有age字段是整型的
+ T+ }7 ?* _: ]$ _
  1. db.users.find({age: {$type: 16}}); 9 Z6 k% R. \- |$ P% v6 l
复制代码

* E! M% [: Z* ~, v1 W% P7 f对于字符字段,可以使用正则表达式 , ~% }* l2 s8 E- `
查询以字母b或者B带头的所有记录 # Y  ~4 C/ \: l1 K6 B# r
  1. db.users.find({name: /^b.*/i}); # v2 L5 c9 [& N3 j
复制代码

9 \  c# [3 s( P' J5 q' v$elemMatch(1.3.1及以上版本) 6 q+ w; m5 {; Y9 z1 Z9 B8 W6 E  X. M
为数组的字段中匹配其中某个元素 / G. Y& I: @- e% q; y

' Y+ d; A& }: uJavascript查询和$where查询 4 i% ~3 V8 J4 T% ^1 X
查询 age > 18 的记录,以下查询都一样 8 R+ z) R( C# ~* G1 m' R
  1. db.users.find({age: {$gt: 18}});
    3 P; u* Q+ L! x3 C: b6 _' |
  2. db.users.find({$where: "this.age > 18"});
      i. J3 Q0 ?/ C- D, I* }
  3. db.users.find("this.age > 18"); + C5 }+ F. L* N+ J6 y; _- Z
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

3 l8 E' l2 V( C1 D  |8 D4 ~* O; v( C# H! Z) l- p# M
排序sort()
! L+ @5 R( _# x. f+ n, a8 C以年龄升序asc 7 i: v" O+ C. t2 o" Z: K
  1. db.users.find().sort({age: 1}); 3 ~! `% b, v5 R9 C4 E
复制代码
  g0 s7 Y+ |3 E$ `
以年龄降序desc
4 l. N- Z; J) x1 Q1 o* Y$ K  C" O" ^$ M
  1. db.users.find().sort({age: -1}); , h3 l. L  k! W: t: M/ c
复制代码

+ P$ l8 I* a1 z: d限制返回记录数量limit() - e" }# ?1 g, J& O
返回5条记录 / d! H# N2 t1 \6 ^4 r
  1. db.users.find().limit(5); 3 g' N( w6 ?& E6 _$ M7 _
复制代码

( c( ?" G0 ]% M7 o9 U返回3条记录并打印信息 3 u5 ^% b- L3 b3 [7 ]# ~1 D
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    9 @3 |1 G! @2 ]2 W2 l
复制代码

7 e$ l* U- z6 S" J结果 . z; j  S# V: {
  1. my age is 18
    1 }" b6 C; K' a6 I! i8 g
  2. my age is 19 6 W6 @, n$ g0 n* ^% H4 w' x
  3. my age is 20
复制代码
8 t8 O% P$ j- z1 V" T+ J
. e, l8 l; H1 c- n* Z
限制返回记录的开始点skip() ! A4 \: U" R+ |4 ]+ C% {
从第3条记录开始,返回5条记录(limit 3, 5)
  I; K" W# F+ t
  1. db.users.find().skip(3).limit(5);
    . T; i" C3 r" a2 l( V
复制代码
: v; S3 j& Z2 ]: f" _1 k8 T
查询记录条数count() 2 M' o& D/ L3 Y: h% e5 K' H$ s; E/ u: p
db.users.find().count(); 1 Z- u0 s( Z5 ]3 M7 W1 N
db.users.find({age:18}).count(); 6 H6 S! K7 z5 l6 h( i% ]3 _/ }5 x
以下返回的不是5,而是user表中所有的记录数量 . _' n( c# V& A  a
db.users.find().skip(10).limit(5).count(); - L/ w' p. l1 u! X! v
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
; S+ M' X3 x! ?0 |5 J, l% d! Q, d
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

8 h+ d/ k% g! C+ V1 ]; L1 _
' P; w& x. H* b% Y, u. @分组group()
# H7 V3 t  h" r' u假设test表只有以下一条数据
6 b& ^$ Q. i# ^" ]+ A
  1. { domain: "www.mongodb.org"
    8 t$ S! ~: ~: ^- o  S6 ?4 x
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ' \; E1 H9 _1 Q  l
  3. , response_time: 0.05 ! F  }) l( D1 T% H9 s: j5 x
  4. , http_action: "GET /display/DOCS/Aggregation" / L) H* {8 W4 @' F; ?
  5. }
复制代码
8 U6 ^3 M! o1 \3 ?! E8 ~  @
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; , n8 f8 b  m# b( l
  1. db.test.group(   q5 H4 B. s0 S$ t' x
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    ( ]# v4 V7 W! g, c- ^8 Y2 O
  3. , key: {http_action: true}
    " a. Q  b( ^% S/ P9 s
  4. , initial: {count: 0, total_time:0} - K6 X# r+ l6 ]# Q# L
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
      }5 a& G0 O+ N- \6 u8 y4 d
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } # Z1 }  W7 l" m# {% v
  7. } );
    - D( R8 {- X! C: [" j! a3 s6 A
  8. ) u$ z0 F& I5 b, W* p4 P( g  F
  9. [ ! M: ^% H* a( u* B1 }& q; ?
  10. { ( I* @; |) V5 W5 d
  11. "http_action" : "GET /display/DOCS/Aggregation",
    # m' c7 N( N6 J" W
  12. "count" : 1,
    7 B' Q& R* s$ b1 f! J& Z) Y. R0 [2 Q
  13. "total_time" : 0.05,
    / @3 \9 e- N! x# k" f
  14. "avg_time" : 0.05 ( U" t# ^0 B6 w, `) I8 ?
  15. }   o9 |- I1 k, {1 C+ n
  16. ]
复制代码

& E+ T( h  y4 Y( f
2 c  h$ b$ K, h0 E9 |7 P( ^% v2 \6 Z/ t- 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
    & O; J. A( c! ]; N$ f, @' l* r
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

2 u  N$ W/ K4 }/ J$ v" u5 G% g1 h0 B! _. \: M
2 R! ?9 v7 i- r
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct
    " X6 g1 ]* T- j- e- }  }
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
1 q: r/ J& F  B$ C! q2 x/ ^1 h6 y

- \3 C2 D6 K# c5 u9 c/ s7 t) L( j4 y
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
. ~; X4 @3 v) b* X1 R2 K
2 B" W. q0 D8 ?& K$ J0 B0 f0 X
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
9 r, O2 u$ Z& Z+ k$ i2 U

. t' q: z/ o" h& f4 Z
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

- P' v/ O8 m+ X$ Z5 J6 g
. u( ~0 q% C6 l- J2 n$ c, v
输出如:
  1.         ( L+ z. n2 Y" l4 K
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

9 p: Q/ r1 |: l1 ^9 g0 X: _9 R, @" j+ j. i% R" k7 m

& S$ {; M( @4 |( v5 C" H: t* d
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"4 t" f" p9 f/ Z0 `8 }: z. y* s
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    ; [. b8 W/ k5 O% r- A/ U. a
  3.        xmlns:context="http://www.springframework.org/schema/context"3 Q; N' r  S: v% Q9 M8 g* D0 h1 E# E9 t
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    0 E( P8 k7 z: R; B, n9 m
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans/ |! Y2 k# v  U2 h
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd# e/ Z6 B# a6 o* A2 L& E7 Y$ M' d
  7.           http://www.springframework.org/schema/context
    8 X4 n* S4 f% `) F" R/ Z
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    . n+ Z  ~6 e/ T
  9.           http://www.springframework.org/schema/data/mongo4 K5 f3 ^+ U" G7 O
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">9 G  L! w8 J2 t# _( X& u% O
  11. * S$ d2 r! }% {& W) ]
  12.     <context:property-placeholder location="classpath:mongo.properties" />3 y7 v1 o; R5 ~9 e0 M4 L( D

  13. ' I% m8 c- O( K
  14.     <!-- Default bean name is 'mongo' -->
    2 {& x2 Z- n/ u% |% I
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    ) y" J" \& A0 T, d5 @6 J* J

  16. " s( d1 m" Z( b  q6 _) J/ Q& h$ l
  17.     <mongo:db-factory id="mongoDbFactory"' Z, y! c8 e( l
  18.                   mongo-ref="mongo"
    # I. e3 l6 u9 Y* ]! H$ }/ |
  19.                   dbname="mongotest" />) u4 O; H" p+ p- Q1 u( J. q$ M6 O
  20. # X+ c* E. M' F  u' r7 ^
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    $ L) C( |( Y8 {! W. E( S
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    ' ^3 z! J! s5 P$ N' `
  23.     </bean>& S6 G* O" o( |
  24. </beans>
复制代码
- G0 U9 v; ]9 w+ T$ n: g/ G/ Q/ m
1 u+ c8 E4 m5 }" E  b6 V; l5 ~; S8 c6 i
maxmin的测试
  1. @Test
    * Z1 k- F* h# b8 j% F( x
  2.     public void testMaxAndMinAge() throws Exception {
    , W$ D1 z* i5 f  t* ^* }1 P$ D
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
      t; k. H* c) e
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    6 A' h4 s0 @' U3 ~
  5.         log.info(result);- R6 d* Q7 u) `: i  H" J

  6. ) p$ K/ y/ B3 d/ L, Z" t# O/ K7 \8 R
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ; i/ c/ T. G/ Z& Y$ H' u
  8.         result = mongoTemplate.findOne(q, Person.class);
    6 y2 _( u$ z1 e" f: Z6 X
  9.         log.info(result);' `  a0 Y5 A$ l0 O
  10.     }
复制代码

, W! @5 _& K8 ]: J' j  D% Y  P/ x4 F3 g
distinct的测试:
  1. @Test% }6 }2 k0 \1 c: M
  2.     public void testDistinct() throws Exception {
    8 t) e( x5 p1 t* A' \
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ! _+ h$ g) m2 P. e
  4.         for (Object o : result) {! t9 Y  w) k3 q) V8 M% b$ b8 k  h" m' `
  5.             log.info(o);3 \$ c& X6 }) N, i. F+ W
  6.         }1 g& F6 T2 {2 `* J! A

  7. * v6 ]$ i( f: l. a7 r" O% a
  8.         log.info("==================================================================");8 G7 w5 j/ \2 p7 q
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    . t- J- U: p$ Q! f3 B
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());0 s& V' ^3 [) a& C9 \- g
  11.         for (Object o : result) {; S. p* E  }5 C$ v
  12.             log.info(o);! Z0 k5 Y% E$ a1 h; K! I- f: X( I
  13.         }& t3 n1 a6 W" G9 l& ]
  14. + k8 {! V4 [8 q5 t& k/ y" ]$ {
  15.         log.info("==================================================================");) |! u/ N4 m6 v- ?, L% r# V" q5 K
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");3 W; @0 W3 k4 l- x) A
  17.         for (Object o : result) {2 V) J) V* W" D
  18.             log.info(o);
    , f% a8 T+ T  m$ T
  19.         }- l# H% |$ i( @1 M$ A9 g( @
  20.     }
复制代码

, }8 }0 O; \7 J8 B3 W# A, E  O/ W
- c7 P9 v0 X2 \# W
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567& ^0 O/ p! a( K& t/ L
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678# |- P1 x2 n7 S' i( `% b4 m
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    ' M- y6 \5 ]+ [+ k( x2 Q% D5 Z
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    5 [/ q" q. M& z4 H7 M. O8 ^
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni" b) o" S1 \, V  [: y
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo4 t$ P, x+ L! V5 a2 x
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    # {7 e  W9 n. w
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    ! `! V- w% e) l4 P. V& B
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567+ P5 \# j- U# N+ N
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    ( T; k% G+ u, G: d: A2 u
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789( I- T7 w2 _% K9 S& |
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654& R5 ?. b. R4 y' f: q. \
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    + s! \! e8 \" M
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    ' J  x) r5 T" m& \4 H, C
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb5 o1 M8 q( N( g; K: X0 a8 J7 x3 F
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc, @% W" f# ~2 I- O) c1 ~# B3 I
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www7 l- b6 J, S  h: \' F' ?4 [, c
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    5 _0 {! M; L$ `4 X- m: Y
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    9 w3 l2 x( k! m" I' r3 f: q
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz, a0 F& Q3 D5 t9 x. `/ \9 }
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr! O4 \7 @5 G# d' r
  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
复制代码
( V  T+ T" Y: Q# \

# r2 I' @- w$ v4 T8 M5 j
这里我要特别说明一下, 当使用了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等信息。
9 `% }) n$ ?( @* h; `
5 p7 E/ M: O9 i1 ?4 b) P7 w

6 r* p0 r1 e) E1 p, o) X- B
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 13:20 , Processed in 0.075555 second(s), 23 queries .

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