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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

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

[复制链接]
跳转到指定楼层
楼主
发表于 2019-7-4 17:21:36 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
版本一:+ l# C4 u" C' y5 h7 P

0 `' b* {- X+ X1 ~5 g1 ) . 大于,小于,大于或等于,小于或等于
9 N+ T0 a; o  b' D% q, [# n. M9 ~/ H' u
$gt:大于5 ^8 N( `4 Y1 R6 ]1 X- Z' O
$lt:小于, b$ P0 z7 U& E8 _7 j9 Q
$gte:大于或等于
7 Q! ^* J$ p5 O; F$lte:小于或等于5 }. v; N2 c. H; X/ a

( c% m( |" [" K) _! B3 R: G例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    5 K1 o' Q$ K4 \. e- N
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    6 M, n% T- e, A* ?
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    ; d8 o+ _# v9 S+ D7 V
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
9 K6 R5 A1 Z7 _1 U3 ^
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});- \! N9 J0 U! v: r; x& L) d
  2. db.things.find({j : {$gte: 4}});
复制代码
4 T7 y, p+ r2 p
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

3 Q( t- j8 v# V" D! F! l, g: R5 [4 n" o  Z: c- x( A8 {& H
) r% l5 W3 G# |
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
( e6 [* D+ Y  B
3) in 和 not in ($in $nin)
6 R; K, P5 k* {; J$ l$ M3 M, ^& J3 {5 D
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
" P8 d! G' u8 r" M8 X
例子:
  1. db.things.find({j:{$in: [2,4,6]}});% S) c4 R, ?1 G* c0 E3 \3 z& K) H! [
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

9 c; M1 p2 i0 |& T, G7 w* C
2 S0 j% K" m/ D
4) 取模运算$mod4 ~5 L7 D- M, W3 g2 F1 D

; }3 U( L) a) e  Y, }如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

! O6 p/ `( a9 V  q
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
! k7 z) S6 J+ g: a- w. r

9 p0 {+ U! P9 a" q' M0 m" V' a/ K5)  $all( m# G2 z  M3 P5 r5 q5 w

5 T# P& t3 S: Q6 i) Q4 R$all和$in类似,但是他需要匹配条件内所有的值:5 E3 g3 Y) E% R8 \. ~7 [

  y$ y8 Z8 W; d; }. w; t如有一个对象:
6 R! j! E) i/ I6 h- ~- g) R3 l* b
  1. { a: [ 1, 2, 3 ] }
复制代码
* @. a0 k' m5 G+ [! W
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
0 X; Q' _% t0 V
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
! o# W; ]0 Y8 c& x6 k" K
, n9 y% Y8 Q5 [% q/ |
6)  $size
! m, ~) j8 o- S
2 K" g: o/ a3 e$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:# X% Z0 }) ]% A
7 k1 Z, e/ }& L6 d" A
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

: o1 R1 N/ |: w! V4 ~( E
官网上说不能用来匹配一个范围内的元素,如果想找$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.
  E6 y4 S# E; `) ^; P5 s2 _  i, A3 W9 E
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    7 d2 z8 W3 N/ [3 v# g& _* T
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

/ k  K4 G% i9 I; v
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    + c5 c' U5 I- @/ U- l1 r
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
& M9 g9 B$ f  `0 G
9)正则表达式
# v+ r, Z; ]! D/ y+ O$ l1 C7 B, K2 Z/ ~; o+ F) J" y) n
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码
9 F1 C, \$ u  s" J
10)  查询数据内的值" c: C$ Z( _$ B! H# e

4 c9 M, F# J" M0 ?! c下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

" O% x4 T& s. K; a1 K8 @
11) $elemMatch1 i5 c1 _- s4 r- m

# c/ v% G; C* G如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    7 K$ t; u( J) G2 v* x
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  3 J1 Y( z: h0 c* d, g' v8 B( u
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]6 k4 o; o; O$ ]' |! C* }; \
  4. }
复制代码
- C2 k; g( H9 r) R. _0 a# y
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )9 o1 j# X& w1 y, i& ^1 `8 i( i
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
) ]# K" o" ?! t* B  H, {( {' Y, \" w, c1 e
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

7 A- y0 V$ ~7 P  @. Q
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
5 \: l' q+ |; m9 |3 R8 ^/ W
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

  q1 V$ x; I( J, [/ t- @, ], {
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

7 M2 y0 e, h) D6 D% b! A/ n
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

# c2 \' Z& ~2 u! {
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

  ~. v! k9 o; E- o! D+ X' n
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    2 k2 W0 o/ o2 z+ W2 _' L% }7 g1 C" f8 b
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

2 Q$ c% a; V/ d* Q/ m$ t
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
( s* B/ W9 f$ j4 i9 @
! U& h. g5 U* q6 X* umongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
$ A( o8 X: \$ J( `6 O2 K: Z9 R* g8 u, q
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
: m( `" S- ~/ B5 K9 z9 x8 G
3 S+ e$ C# m8 B, H. j3 e6 R) r版本二:
% C5 |7 ]. `/ V7 l. P# p8 s, K8 {
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

) i$ h: N% m+ M1 @) f- ?. h6 }
  1. use admin
复制代码
/ ^% {1 @8 x6 J; I2 o! a
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
. n: j- i* Q* y
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
0 V9 n5 J: y+ Q) n9 M" r4 ]
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

7 @9 D' `/ F4 P9 @$ J/ }  d% ^
         5. #删除用户
  1.           db.removeUser('name')
复制代码
3 E5 l; ?" a5 M3 ?( O0 U
         6. #查看所有用户
  1.           show users
复制代码

8 M+ H; ^8 b5 r1 z6 e( N4 R
         7. #查看所有数据库
  1.           show dbs
复制代码

7 M% D+ h* H1 e) K3 v& C
         8. #查看所有的collection
  1.           show collections
复制代码
3 f9 i+ H; A2 k* a& z; L2 j
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
. o  C7 _3 n8 C2 K
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

' }4 [& H" \, R. g
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

- a$ r1 g9 S2 k+ ]
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
8 G) k+ l" @! }+ X
        13. #查看profiling
  1.           show profile
复制代码
1 X& n8 p% ?% Z6 E+ _, x. x9 K
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
* G! u, x7 b: `+ p, \7 x
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
! m0 G0 K$ n4 f( N* q9 a6 \
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

4 o% s3 ?# E6 ^: Y
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
. j9 y$ q) ~9 h! j8 g
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
" c# L1 U! [% {- O; n- N
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
8 ]2 V$ A9 I9 Z
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

: T& \" A) b6 Q+ Q
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
! x) g7 i: \) r, ^" S( d2 \3 C' b
   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()

! B8 q2 `9 R3 ]- r
6.  高级查询
条件操作符   D! G5 F$ [0 Y0 v; \
  1. $gt : > ) [' M0 \; P6 [: H6 t8 D1 I
  2. $lt : <
    9 d1 |; Y: J8 ?" ~5 {& ~
  3. $gte: >=
    3 [7 ^0 x; h/ p# K
  4. $lte: <= 0 ~% w6 M! p9 P3 u, H& Q$ W
  5. $ne : !=、<>
    . Z# k- _: f2 D4 R
  6. $in : in
    * Z+ e; W0 ]& F7 r% ^+ l
  7. $nin: not in
    & g$ W( O* g/ R$ {- y
  8. $all: all
    : G4 [8 T( U3 R2 g3 U; \
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

- f9 Z9 m' y  L; }3 b  x( @" M
: u' p% B/ w7 E* [( L: k查询 name <> "bruce" and age >= 18 的数据
* S& ?) z- B4 w1 K( X
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
7 Y+ a; `4 W- w# w& k! O% S
  n+ Q1 K$ F/ Y. m5 D+ y
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 8 Z* K$ M. _0 @2 r7 _5 l$ o
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
9 {/ l8 W  h9 Y" y, b
/ r, o3 L* K$ y
查询 age in (20,22,24,26) 的数据 % I, {4 A# c* f4 K8 w1 K9 H
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
4 [  x/ p# b5 U! Y1 w& o
' W. r/ _1 d$ C
查询 age取模10等于0 的数据
% r4 S+ A7 o" g# w1 L3 n* U
  1. db.users.find('this.age % 10 == 0');
复制代码
, y: f! g$ k, `- d7 |. ~% c  ]
或者 ' s6 p5 F% B' |! I: K# n
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
  c: ]9 j6 ]6 k8 y! b7 C

' g1 Y; V* U; y' q' A8 I匹配所有
4 k8 Y! ]. w2 d, f1 U/ t, L
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
% ?% \) P0 d2 L: A3 y; B$ y! _
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
2 \# |! U/ o3 y6 e9 D1 k可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 4 I2 V( B6 u9 g+ x2 ^0 h
* y/ ~1 @- z: v  d/ O
查询不匹配name=B*带头的记录 ! h! p. ^2 b+ P% r2 D, ~
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
; G# `7 k2 N8 l) V
查询 age取模10不等于0 的数据
. D% p  a6 ~$ s) x8 A: d8 F
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

' u& u2 U4 h9 L$ W# X% L0 p8 C- _) y) T1 e5 E
#返回部分字段
3 @4 F/ f3 g  D+ Q2 a% R选择返回age和_id字段(_id字段总是会被返回)
. K6 H+ s# y2 F4 s
  1. db.users.find({}, {age:1});
    / S& A% Z" s7 \9 `- Q9 v+ R
  2. db.users.find({}, {age:3}); + o( `8 d" t; ?* ~: W- ?
  3. db.users.find({}, {age:true}); ; F- _# p0 v$ A4 Y$ s8 D
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

" D$ ~" D( C; z0为false, 非0为true
: y" E8 X, P3 W9 |8 v
1 W0 p8 K6 j/ k- p* [( O! Z& Q选择返回age、address和_id字段 ) T' \2 D/ r" k( f' D: a% O
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

+ O0 H5 h4 B' m% R. P  ~) Q$ E" V) ]; w+ [" {
排除返回age、address和_id字段 , P7 S) B4 p6 w9 c
  1. db.users.find({}, {age:0, address:false}); 7 j& J! y& `2 f2 F
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码
+ g/ M# E0 W5 U- r6 H) [
) v- |/ R" Z- o; j3 x
数组元素个数判断
/ ]" G* a- R3 P8 t: T$ ?4 D" z对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
- \, |1 G2 h# i# B/ A匹配db.users.find({favorite_number: {$size: 3}}); & ^$ u5 G9 R  v0 C+ L
不匹配db.users.find({favorite_number: {$size: 2}});
2 _+ r/ V4 Z2 s7 n$ N+ l' ^" s+ ~$ Z: p8 D. d
$exists判断字段是否存在
. H0 w+ P; R& ^4 D2 k& {6 f; J/ i9 m查询所有存在name字段的记录 # l7 P* p" ?& S1 X3 H
  1. db.users.find({name: {$exists: true}});
复制代码

, Y. ^' I; f& k- k查询所有不存在phone字段的记录
. c* P- {; E4 A# l; |3 V
  1. db.users.find({phone: {$exists: false}});
复制代码

/ L7 u* T% M8 m2 }' _6 x+ t$ {3 m, l, y$ _
$type判断字段类型 2 I( h8 t6 n+ K. Y
查询所有name字段是字符类型的
2 r0 S0 c3 H+ c# l1 e: d
  1. db.users.find({name: {$type: 2}}); 8 T  t! M+ b" q% y/ e! \/ w3 I+ |
复制代码

: V# _8 c0 u+ ~8 u" R& d7 C查询所有age字段是整型的 3 ]( M$ [( _9 D, \7 F: u
  1. db.users.find({age: {$type: 16}});
    : ^$ U0 |8 U$ L6 ^2 v# q% u/ l+ T
复制代码

+ v$ K4 b: g6 u  x2 W, l3 ~% b对于字符字段,可以使用正则表达式
& j6 I; l, C( F6 l+ D) c" _' M查询以字母b或者B带头的所有记录 7 B6 S% F; \& _' }
  1. db.users.find({name: /^b.*/i}); / N0 n3 p- L' F8 W
复制代码
6 e# F1 I# _7 e0 t. l! _
$elemMatch(1.3.1及以上版本) 3 @: y: I, g7 {& X4 J7 D
为数组的字段中匹配其中某个元素
# L$ j8 Y# A: O6 Q8 p) D
0 A8 W; W1 ~$ E5 [& s& jJavascript查询和$where查询 6 {; _0 D1 O( w' D9 I' R! |
查询 age > 18 的记录,以下查询都一样
2 W% Y( K: u2 W+ B/ e0 [
  1. db.users.find({age: {$gt: 18}});
    ' A/ C& x1 t- ~: o( {0 Q  M
  2. db.users.find({$where: "this.age > 18"});   s/ g: k. F. \/ R/ u( z" H* _
  3. db.users.find("this.age > 18");
    4 F3 J- ~; A4 i6 v. e! M* g3 R
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

; u0 \0 l5 [% j: ~' D# c
' ~( W5 J1 o9 s! ]! R排序sort() ' _; r  ^: b) z1 M  S* ]
以年龄升序asc / h* m$ t$ d% g9 b6 L9 z
  1. db.users.find().sort({age: 1}); & R$ E" R7 b  U
复制代码

. g: b. w) k( I! m0 N9 Y' {, f/ w以年龄降序desc
& p0 o' D7 k9 s- \, n
  1. db.users.find().sort({age: -1});
    8 V" m4 @/ J! F# I  q4 l
复制代码
- F. m/ a) n9 z$ N2 H$ K$ l) B
限制返回记录数量limit()
& ]+ u+ B7 ~4 q! U: H返回5条记录
5 L. P0 d% d$ B3 L- N% o
  1. db.users.find().limit(5); * M( p8 x& z+ ]. e6 w+ e
复制代码
, Y% i- a. ]* \6 u- C6 \& t4 L
返回3条记录并打印信息 4 p8 @9 }; T& {) u8 Z. x; x/ M
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
      s: h- K. O5 s0 m( y" p# W
复制代码

/ D2 y6 G+ x$ V结果
6 f, }- W+ B! d& Y
  1. my age is 18 5 b/ z, L9 A- }1 @- O/ ^; q
  2. my age is 19 ( J% @+ v5 ~; M
  3. my age is 20
复制代码
" w3 F  y# m: \  X7 r8 p; s) Q
0 R" Z1 T8 j  k% x0 o. \6 N8 s
限制返回记录的开始点skip() 3 b: d: J9 R" [1 u6 k) d0 v8 `) u
从第3条记录开始,返回5条记录(limit 3, 5) / I0 b1 q* d4 r5 U
  1. db.users.find().skip(3).limit(5);
    * W& ?- M% D% \# L  ^3 q' Y% h: \% l
复制代码

. @* ~  \$ e5 I8 [7 s查询记录条数count() - k% q& h- `$ ?2 i" d5 ?
db.users.find().count(); - A$ D7 H2 O, b0 |# i( I
db.users.find({age:18}).count();
8 L7 F+ B) t" ^& C% Z8 S9 d以下返回的不是5,而是user表中所有的记录数量 # E+ {1 o% O4 f8 q. {' T% l
db.users.find().skip(10).limit(5).count();
7 L3 N$ Y. o% v' u" _4 F  E如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
& C! s& D5 X' g
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

0 L0 B9 ]* O% z0 l+ R# H
9 r( {1 e. H7 @0 T" h4 T& @6 b3 k分组group() # D0 t* _6 e8 c% Z! v$ T3 I+ V
假设test表只有以下一条数据 . z7 z: r% x& H# ^- B
  1. { domain: "www.mongodb.org" 9 ]; [7 t6 a) I- E# l
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    + L" a6 c( j4 @: \9 [5 A0 ?
  3. , response_time: 0.05
    4 {5 `- j$ x, _
  4. , http_action: "GET /display/DOCS/Aggregation"
    $ L9 T% E- X* K( M5 R8 [0 B
  5. }
复制代码
: f  g+ [' a0 E2 t; `4 e
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
. F5 N1 n, ]% z. h) W) W% o; j
  1. db.test.group( * @+ [# Z4 v, T$ X
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} & T( _+ E, F8 L4 ^9 M7 G) a
  3. , key: {http_action: true}
    - t( w! s# Z% z
  4. , initial: {count: 0, total_time:0}
      V4 R& t" v) ^# V) m+ s- y3 E2 L3 B
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    4 a/ }( Z2 t# a" x) R$ g& ]- C& }
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    # A2 i# R, |  \9 n; k
  7. } ); # [7 D' t6 l; L% D, R5 k* r2 }5 n
  8. " ^/ I# s# a/ W( f9 |3 s2 P
  9. [
    5 D; }3 V' o! E0 e
  10. { ' o/ s/ v- j0 W* L# e- a# r
  11. "http_action" : "GET /display/DOCS/Aggregation",
    + h; J, x9 ~, w0 {* Q6 B
  12. "count" : 1, $ G& L$ I. S( {( o' V$ n2 \5 r" ~
  13. "total_time" : 0.05,
    1 O9 D0 i5 K" j
  14. "avg_time" : 0.05
    ; e. i) `4 O2 }
  15. }
    1 x6 l* b# @9 f; ?4 z& ^9 d
  16. ]
复制代码

) ?" `# A; Z8 r* M$ G# X' D2 l" s9 h+ j5 l; w: }& j4 c/ y" Z7 Q
# g3 N. |( H& C: R) g; l
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 和Min7 c  {% h4 m( ^
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
+ Y2 ]  o/ `% Z+ S/ L, I

$ c% t7 @+ p4 D) D  J! k

- E3 ^0 o( t. y9 o
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
  • distinct0 c( Y# Q( Y) Q) H$ t, m
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
0 ]4 j! I! t) D
6 }8 H& \* L8 r# L
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
, Q( I+ ^7 u  t$ P, l
5 p6 b5 I0 \; ^
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

. X9 h1 S* F2 Z0 a: d! {% u; j4 r, o! o, d6 g4 c. H# @
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
$ G) v: P0 |1 l) |9 A- J! E

- V# J$ J2 {/ A
输出如:
  1.         
    4 c8 A+ u/ ]0 V( `  b' E" C
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

4 A+ O! k* s" h3 U) @8 X4 T7 ]3 C1 d7 k  X& e9 f1 k
9 q/ r3 ~7 r9 H1 G, z7 Y5 F
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    ) Q6 P3 y! v% z2 Y$ e% x. m
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    + W9 c3 l+ _* n8 g  @5 ~
  3.        xmlns:context="http://www.springframework.org/schema/context"3 E9 W( Z3 s2 f. T6 x- b
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    2 J1 g3 ^0 m) D( V
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    5 h9 N3 n. k; F: D) }
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd/ M/ ^" N, \9 Q( l
  7.           http://www.springframework.org/schema/context
    1 L, h. J& z$ i+ |* x
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd% j5 ~. b) I) c* A  ?5 j. l9 P
  9.           http://www.springframework.org/schema/data/mongo6 k) Y- l6 M  I; E1 c8 U' h
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    : b/ t8 C; c3 G; @9 |8 H9 ]

  11. 1 l# B8 J$ g9 _. A
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    # R/ b7 `/ t$ N; x
  13. * J, {4 y" z* R' z
  14.     <!-- Default bean name is 'mongo' -->5 f' k. M. G6 ?1 S$ V8 \
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    : F; C- Q0 d; h7 b

  16. 9 ~: C  M% m2 y, L( b. ~5 q6 K* a
  17.     <mongo:db-factory id="mongoDbFactory"2 ?) w$ u4 H! v! `+ S( t
  18.                   mongo-ref="mongo"
    & P7 Y* |# ^# B! T" ?. b2 l* D
  19.                   dbname="mongotest" />
    4 f3 a/ O/ t" C  i/ _/ e

  20. 0 C8 A( ^8 r2 \; k; _# G8 C
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">3 `0 f; s6 T* O
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    % b/ V6 O5 s  J6 N; T: ~1 f
  23.     </bean>
    0 M' U* N& i# @9 j# W
  24. </beans>
复制代码
" b( K  D' t+ T/ g9 Y  b

  P, h  r1 l+ X5 X5 A0 {. Z
maxmin的测试
  1. @Test
    2 Y: A  A; G3 u  h, m
  2.     public void testMaxAndMinAge() throws Exception {
    $ S: k& n/ R3 \1 a) ?7 ~
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);1 ?- n4 @3 E; l; [
  4.         Person result = mongoTemplate.findOne(q, Person.class);8 P4 U$ ]& y7 r' k: N
  5.         log.info(result);; u  A: p3 F4 A- x1 U, c
  6. 3 u% |( B6 T* F1 B( a! f( o
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);* M! v% R, @1 q: r! o
  8.         result = mongoTemplate.findOne(q, Person.class);7 r9 y6 _1 f1 B
  9.         log.info(result);/ w. l& }/ _0 D( ^+ a
  10.     }
复制代码

, c4 H6 X! ?; w/ C1 Z& |' O0 u5 F6 g6 U; [6 n
distinct的测试:
  1. @Test( K4 E2 F) z' x8 s
  2.     public void testDistinct() throws Exception {
    $ _* l2 I8 W5 v5 D. y$ T
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    1 u; [" n- n+ M
  4.         for (Object o : result) {
    # |. Z. Z$ X" U' P
  5.             log.info(o);
    4 @" L3 v6 Q+ m) l' U8 D
  6.         }
    - s+ E# `/ X7 d0 s3 H( R

  7. 5 F/ o- \5 D! m! `/ X- _, E
  8.         log.info("==================================================================");! }3 T  _* t* P; m, |0 o7 m/ `
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    ( d7 ~: }3 a" f) @
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());* N. }; z( d+ p5 y  F  m' ^$ o# `
  11.         for (Object o : result) {
    # [. Y, t! j& e) L/ N
  12.             log.info(o);
    9 a, y( Q! k7 @" U5 o# S5 c* ?3 s  A
  13.         }9 J" r' }: i* {3 i2 ^6 S3 v
  14. , m& {1 C& ?/ \+ H  T$ K
  15.         log.info("==================================================================");# H/ `" D  E+ H& @
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");8 i* A& v( ~% i* H# M/ u
  17.         for (Object o : result) {
    / P, \' h1 p( E* ?
  18.             log.info(o);+ b" J& {* s# G) l( K  ~
  19.         }4 W) l  ^! [0 P3 _( V
  20.     }
复制代码
# h. C! }' U- g1 y3 \' @+ F' t

7 M8 E* u+ ^0 G: h  u3 ]& @: t
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    1 o. o; v7 _* l, V. s9 F3 Q0 C1 C; y
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    0 Z  J: w2 w7 \+ i6 g  {; F- N) e: |
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789: Q0 {/ v% e2 l9 k; P4 |* s0 h
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654$ u% V* D! \$ y( G$ H. L
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni9 N. \# h" Y8 P) D$ o! J
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo" ]5 r. r3 q: s. l3 d% L/ B- e
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456* M* p( y" \+ G
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================: l8 H5 q0 R6 x9 W2 T
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    ! G$ u+ l' b2 X  {
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    * K4 h2 q1 O' F4 ?" w2 s
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    ( F: A; P( t( d/ F6 d4 {0 L% y
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876545 X& F' ^( D' F
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================0 p5 d6 D* h% m7 v# A9 W& F
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa, K! A5 y0 D6 E/ j' M# `+ j* h# E
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb, ^! S) F: F6 q) v6 @; f; @
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    2 |( [" Z! L- L# a$ }" a
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www9 O* L, F6 c: i$ R+ m3 k% `
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    * v4 I6 j/ \! m  O9 ]* m2 I5 Q2 b
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    4 l3 V2 l3 y5 X/ a* O
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz; x. c  W/ g$ Y+ U! o! @
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr1 R5 _- x" q4 s% |+ D" Y0 U; w
  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
复制代码
1 F) q1 f1 S; G! {* d
: j+ p+ ~4 q( ~$ o
这里我要特别说明一下, 当使用了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等信息。

0 h# T6 k! p! [" y6 |; K& t3 j8 ?6 f1 B9 v* w* j; ^* m
; r& o/ z3 e$ L* k
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 20:55 , Processed in 0.065541 second(s), 23 queries .

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