cncml手绘网

标题: MongoDB高级查询用法大全 [打印本页]

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:0 Z) }  W% x$ D$ H

9 N" p5 k  Z9 U, P- ^1 ) . 大于,小于,大于或等于,小于或等于
  t- ^4 r" B. b* a, Z, ?3 E$ U/ N# x4 y" A$ B5 Y2 c5 D
$gt:大于6 R) n$ r: r; _3 {6 x; s& r# I
$lt:小于
- o0 |' g+ s- G' J+ e$gte:大于或等于
& h( U7 P' @* R& a+ x$lte:小于或等于" _# ]+ j& J" A1 C
; y/ X9 Q" E7 f- _
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    ' S! X% ^, D3 `' V  X  ]
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value' Q3 o+ T7 q3 r! L8 E$ L! ?6 J  u
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    8 y9 V6 D$ g+ |# H
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

) B! l% D$ Z- k$ r& [5 q/ X  l8 [
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});, k1 \$ V, Z5 U9 {% ?& F
  2. db.things.find({j : {$gte: 4}});
复制代码
8 K* z9 D  Q% H$ Q8 O7 L! ~
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

/ `* K! R; J: n+ `
% F' F7 `% z; c" @3 f  ?% V  N, x9 @% a* b7 S1 @1 L
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

6 y. ^5 y0 y* O* b
3) in 和 not in ($in $nin)
* r9 v( z3 H. i2 Y8 l+ b# t4 e  s; Y0 F+ w: p1 C' ^2 j: p5 B( ]4 e7 S
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
  B4 Q0 ~3 W$ @! V& J3 q8 v( Y* q
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    , F1 k+ R  y! n/ n  Q7 g) L
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
5 K: ?* ~1 n1 W# Z2 s. _

. s5 s" z3 F# m- X4) 取模运算$mod
% I6 b0 ]8 F0 \+ t: Z, p& {/ o. R1 A8 d/ m
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
! a: h2 M! m: l! j0 l9 n. s
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
! u8 n4 N# I1 y3 @
- e6 F* V6 O+ R$ u/ j3 \  e& C' d
5)  $all
! R' D7 q- r9 z! C
- a( }4 A1 t0 |% I: F4 H" h: |- u$all和$in类似,但是他需要匹配条件内所有的值:
, @' @' e9 Z8 U  i$ {3 n/ j# P: S' o! f3 w5 o4 S/ z& k
如有一个对象:9 g1 ~* `3 d" E6 i3 ?0 T' v/ F
  1. { a: [ 1, 2, 3 ] }
复制代码

" X  k8 u6 L; `% [# ~& j" K6 H, A/ U
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

$ @) {. p! H1 x; F
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

* \. S$ N7 C( f' _6 U7 c6 G

3 _0 H! p. f4 n+ H' v4 |/ q3 [9 N6)  $size# P% w- C6 B0 ~6 H4 n/ S
4 G- o9 C: q) N$ B! U2 E3 {  Z8 A
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:7 g& V9 d1 d( T( T

9 e2 P4 b& o+ k. b$ j; m下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
, r7 u1 N5 h7 t/ U/ G, _1 ?
官网上说不能用来匹配一个范围内的元素,如果想找$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.
- g3 A+ l) r( a- J6 `5 S
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回& h& k' |7 f" k& c+ z( Q4 w8 U
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

6 u: k* Q) \4 s  \3 Z' u8 K4 z
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string7 L0 J' H& @/ v+ w
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
% C$ T9 B/ h. b3 _- V7 g. H& b
9)正则表达式
1 C! L. h4 N7 ^6 s4 |
- r1 q, ]" j: i" z) z. S0 Y! ]mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

' n2 a4 n" K1 Y, W; T! c9 ?
10)  查询数据内的值+ `& M, [- O! ^) _, R# S* m

! p0 s- b' L4 E: _% w下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

# V8 x, c! x" C1 k  @( }. ^
11) $elemMatch
) V- k# {- z6 w/ Y" ~
, P. t2 }8 r( O. z: e如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) # t$ v+ D( q) W" A- X( p
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  & X6 Y9 A/ L$ r* J5 z
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    6 b( f7 p, `9 V* T& \
  4. }
复制代码
5 Q. P: p3 t2 |/ l
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )# `6 J' J! J0 |' y% H
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 3 r0 `4 I# S; y# K* f. t

6 L% c7 {# w# D12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
- w* C$ @" O) O; A
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

9 m, {) C" y; K( M: K! R
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

3 G4 G$ w( K+ G- k3 A3 o( C" r6 k
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

' ?/ M' v$ q* ]5 ?( U7 f. v
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

: Q3 \9 y% r; l3 Z+ \
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

: f- h8 L+ Y& b+ B
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
      g* i1 j9 [8 j! B2 B
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

, ?7 K4 y0 W* x
mongodb还有很多函数可以用,如排序,统计等,请参考原文。& o" P; E, `, l: O& L

  i# m" ~9 Z, @/ d$ i  Vmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:# {1 _; Q6 D% ?6 Q

1 H0 @# b( i) I9 t$ j0 @" q7 [' hhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
3 z( e2 q. ?6 s- \7 l! j, \( g4 Y& I# \. k
版本二:# C: E% [& P! N& a6 h& _  u
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
- S1 r5 ?& m( C4 X+ D
  1. use admin
复制代码
& P0 ^# l; h) K5 S
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

. ^1 x3 q# a$ Y4 A. J4 m
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
4 m  b7 N4 Q6 U, b' v7 b1 m: u- n
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
) a: _. A$ |4 x- T$ ^) A4 B) L
         5. #删除用户
  1.           db.removeUser('name')
复制代码
% S. g( ?4 W9 k* @
         6. #查看所有用户
  1.           show users
复制代码

4 K5 K3 k8 Q, Z
         7. #查看所有数据库
  1.           show dbs
复制代码
; d5 k! [, F# ], _% c5 k$ S
         8. #查看所有的collection
  1.           show collections
复制代码
, {; P. b0 v0 s* [6 r$ M
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
7 w  `+ f3 }. ?6 r! E3 a! T* v
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

+ B4 I3 U2 x; w' ^+ {8 e$ ~& y
        11. #修复数据库
  1.           db.repairDatabase()
复制代码
' r# z! l# v2 A' X
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
, x: F2 f/ b) d' U0 o
        13. #查看profiling
  1.           show profile
复制代码

+ t9 S5 I, p* O$ W: u
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

1 z3 q4 K6 S% P; I# b& y: E1 s) P! T
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码

7 \* \" b6 y' a# r+ f$ ^7 {
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

  w5 Y# T4 w0 e$ K0 f1 |
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
( n+ z5 D& m8 s  k0 h
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

2 t+ `+ Q" G4 y/ _
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
2 \/ p: [/ |  g8 J( P1 Q
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

- v" @+ N+ t+ \/ I/ y4 a
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

! e' Y* G) s( c* L8 ^- ~
   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()
7 E+ z: H" Z8 e" c# j9 L
6.  高级查询
条件操作符 . @. c5 a' @) o) _: r
  1. $gt : > 4 K" n/ s3 X1 J+ V  `( Y" J( w' {
  2. $lt : <
      v- f/ Z2 h' o9 r  `
  3. $gte: >= ' y. ^$ f5 i. q
  4. $lte: <= ( b, S4 {7 @8 \5 {
  5. $ne : !=、<>
    ! B3 n' s! S( z+ i0 j) l) l
  6. $in : in
    & @0 \2 R, b# t2 K/ s8 E0 Q1 R: b
  7. $nin: not in
    . l2 D* A& b- ^# U% Z8 a
  8. $all: all $ m5 }3 V; `$ W8 |4 N: a+ j
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
( `! m# x! B2 y; Y) V- n) g/ H
! j1 K9 F% O& O9 ~# p- O
查询 name <> "bruce" and age >= 18 的数据
- o! \( G6 j8 u) L$ E" ?  A$ u
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
; d3 b: a$ d- I

8 o& Q; U5 I1 g: J6 n查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 ) l$ ]  X3 P' h. b$ F7 f2 b7 \
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
. D/ X' a6 S* w1 {$ g9 Z
, B9 ?# [. x8 d) X  b) m7 o7 Y
查询 age in (20,22,24,26) 的数据
7 r  a( @1 c7 x3 }0 d% e
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
; s+ Y! |- n, p! a7 X' E

) Y  U" n' q3 o查询 age取模10等于0 的数据 # i: U% J( O2 Z9 I+ D# I
  1. db.users.find('this.age % 10 == 0');
复制代码

3 e4 D6 x6 }! p) F! R4 x, Q或者 3 z& P, R4 i" C0 F: ?
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
; n2 P! ]1 E3 k/ Y3 D

1 n& n! [7 {* e: {- q) U% ~匹配所有
2 U; v3 i& M4 J( p- J/ h3 O- y
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

( {- \" K" V& P/ t可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } / ^) {; _: I. X0 l- y1 @
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
! c$ d# F* \+ \# o4 c/ P
  C! d# M* w: Q. [9 {" N查询不匹配name=B*带头的记录
4 R# W# l8 Y# _6 ~0 T/ C
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
, B2 o8 Q# M# g( o2 F
查询 age取模10不等于0 的数据 + l' i* x' b6 I% g) ]; R  `+ L
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码

1 j- i" O# h6 \
! }! t/ T5 ^: b2 [& X5 J#返回部分字段 9 Z7 J4 c( m/ N' k: T+ u
选择返回age和_id字段(_id字段总是会被返回) # o5 ]# ~6 K8 W+ S  F6 \- p
  1. db.users.find({}, {age:1}); - O& z7 L/ x+ p1 g+ i- f) }
  2. db.users.find({}, {age:3}); 1 B  _7 O$ y3 F& d/ M
  3. db.users.find({}, {age:true});
    # b0 |( J- P2 E+ X" C2 q3 ~
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
0 ^2 q# }" n3 v6 t1 b+ ~
0为false, 非0为true / d) i- r$ x( i; K3 ?
5 v8 y- t3 U& n& D6 L% j  ^
选择返回age、address和_id字段
. ^" H4 I( W+ a
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

9 V5 r* d5 C: d: d, u$ G# l9 g2 N" ]; m; ?- M, \, T! D3 U
排除返回age、address和_id字段
- k) F+ Q  J6 ~- W7 h
  1. db.users.find({}, {age:0, address:false}); * {2 I5 p& F2 i
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

& e$ t9 C, m' Q: `: a
% e/ d+ z/ l- {- d1 X数组元素个数判断 , ~8 I. Z, \* F& }, Q! Q9 _
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
+ l+ c* Q" S' n8 c1 _* N! f匹配db.users.find({favorite_number: {$size: 3}});
2 n7 u: p- f5 j( e6 ]" L不匹配db.users.find({favorite_number: {$size: 2}}); : I( ]5 g  G) n
- N6 C0 E. r+ W
$exists判断字段是否存在 1 p  @6 f4 t; O3 ~7 ?0 l
查询所有存在name字段的记录
# ?) d* u; m( b  f/ M. _; H2 S
  1. db.users.find({name: {$exists: true}});
复制代码

% t  G! D9 w6 g* h' M% C+ X- ~" _查询所有不存在phone字段的记录
0 V" u: ~5 U. ]% X% h/ a
  1. db.users.find({phone: {$exists: false}});
复制代码
  q6 i0 {0 c# p% [1 ?+ j8 y! k

) w) N9 W: ~( E$type判断字段类型 ' E4 w. R# W& ~8 H
查询所有name字段是字符类型的
& i, |1 o$ \& k2 ^; d7 y. M2 A
  1. db.users.find({name: {$type: 2}}); & \# `( E- o$ m) K( l$ c, f
复制代码
" t4 ]5 g; J% t: a8 N- U- t
查询所有age字段是整型的
( p0 Q/ k7 l/ B$ J6 J) N
  1. db.users.find({age: {$type: 16}}); + h8 R: g7 E0 w" j3 ^% `
复制代码
, L7 z' ?: Y$ J( c5 T4 j
对于字符字段,可以使用正则表达式 5 J  A8 C. I  J9 @4 H) C
查询以字母b或者B带头的所有记录
. u, w( }$ ?% j+ ]* `/ l: N2 L, S
  1. db.users.find({name: /^b.*/i}); 2 I* X: L) _. Y9 Z
复制代码
/ ^; t; q; O' O
$elemMatch(1.3.1及以上版本) 0 V# c2 O, s/ H; Y
为数组的字段中匹配其中某个元素 , r, p0 B' s- F! I

3 a6 o0 J6 ?: g% b" VJavascript查询和$where查询
# m% |5 ?& M7 k8 G查询 age > 18 的记录,以下查询都一样   f: }2 k" Q* X8 Y; T
  1. db.users.find({age: {$gt: 18}});
    1 E1 p0 S8 r) ^* }
  2. db.users.find({$where: "this.age > 18"});
    - o# R# L$ X$ E) L
  3. db.users.find("this.age > 18"); 3 V& ]8 p5 w0 x3 }3 h; a; p% @
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

4 p$ `' T5 u; A' B- o! m2 B$ H' T) j2 o4 R+ r" `. I0 H
排序sort()
; D$ T- s4 {$ C; }/ m6 d3 V* A以年龄升序asc
$ e$ G& A' h! R6 `# ^: e( b( d2 r2 X
  1. db.users.find().sort({age: 1});
    0 {& x# q6 ~2 s9 g" |0 S; ^! x9 ]
复制代码

7 G' }7 V; H# T$ X8 N- }1 f以年龄降序desc
) {) Y  }4 ]- ?' f2 a
  1. db.users.find().sort({age: -1}); + U5 ?  K) ~9 I9 u- \
复制代码
# g6 c( f4 D9 d4 p
限制返回记录数量limit() & ~$ J* W4 C# E
返回5条记录
$ m. l# M& e- C/ Q; E1 T
  1. db.users.find().limit(5);
    6 E- G- [) {7 d: V' L. t
复制代码
' l  |, D8 G3 \4 f7 C5 h" o
返回3条记录并打印信息 " U; K4 q0 I! w
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    7 A" m  ]) ~3 J4 N  \$ i. |! L
复制代码
" Y- p$ o% p$ r: T2 M+ l9 \. G, x
结果 % F; F* Z2 j. E; K4 D6 T' J6 G
  1. my age is 18
    " ]. I2 g8 a9 w/ a$ R' `
  2. my age is 19 0 ?0 o$ @$ S) e3 y+ v1 ?$ Z
  3. my age is 20
复制代码
/ d2 ^/ ^$ |) }/ J8 x, i' X* E, f
6 k2 C! Q5 Q2 K( w. I
限制返回记录的开始点skip()
3 X  ?7 M7 X9 W* e& S1 Y# ~8 T& u  j从第3条记录开始,返回5条记录(limit 3, 5) 6 v, R# \: ]2 ^- B
  1. db.users.find().skip(3).limit(5);
    ' H0 G$ }% V; n/ t
复制代码

1 t" B1 G. g! l) R8 ~) h查询记录条数count()
7 H* o, e% u8 Tdb.users.find().count(); % b2 p6 m2 M5 |" g9 Y' L' j
db.users.find({age:18}).count();
2 N' r1 |- E5 L  \$ F6 v! |以下返回的不是5,而是user表中所有的记录数量 $ S5 Y, C7 s+ U* s6 ?- Z, b
db.users.find().skip(10).limit(5).count(); 4 _" G5 g$ G7 ]% W( b
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
6 {, O7 c1 Y' d" D! [
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

# x5 \: o: s+ a3 h# f- ?6 P% d5 z+ J
分组group() 1 K3 x1 ~9 T. `3 ~; n4 B) C
假设test表只有以下一条数据
" u0 {1 D& q3 s( b
  1. { domain: "www.mongodb.org"
      L4 V' F/ h/ F8 f
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    7 n& A* J  J. s' x9 w
  3. , response_time: 0.05 ) |4 F' R# [7 z- Y3 U, `
  4. , http_action: "GET /display/DOCS/Aggregation"
    ! C" m: ^  ?2 O7 A0 s0 r1 n3 M
  5. }
复制代码
3 b" i7 q1 M, [3 B( X$ f
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; % |8 r  Z$ l' a9 y% T
  1. db.test.group( ' x0 G  {# B4 x+ z3 s  O
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}} : k2 @# A9 Z( H, D& J
  3. , key: {http_action: true}
    1 W1 G  S/ ]( _+ u# c
  4. , initial: {count: 0, total_time:0} : L' @2 C5 s' @: M! C$ |
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    - s7 K+ Y+ i; h% M6 [
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } . g  F, ^6 a& {* {7 q
  7. } ); " F( G. e' C0 o- B; b+ _2 t( o

  8. 5 P! c1 s* G5 w3 t# m0 L; B6 U9 V5 N8 M
  9. [ $ E$ ?( N2 Q1 h" E, g) S$ D
  10. { $ I0 h% P# i- e5 z# u) i, p! R! |
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ! x; u. F# C1 ], O7 W
  12. "count" : 1,
      Q0 {' ?' K6 m$ k+ }3 U6 B! t$ V
  13. "total_time" : 0.05, & ~9 w* D1 B1 ?1 j$ c) l4 S: s
  14. "avg_time" : 0.05 * _, Y( S# T4 W0 T
  15. } ! H; e1 L7 X" t. r4 K
  16. ]
复制代码
' E6 _5 f3 }/ ^! j# f2 I1 S

" v3 ?: W1 ~( [- `
6 v4 a; Y+ \3 J5 _$ U! u) w$ ]8 d  MMongoDB 高级聚合查询
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。
见:http://static.springsource.org/spring-data/data-mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoTemplate.html
不说废话了,我们直接来MongoDB吧。
  • Max 和Min  w, W5 {! l( H' S
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

& d, d3 W2 C8 C9 {2 X; f) l' c  k  u5 S& X
% m# z0 C8 d  l
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
9 I) R1 y. d: p
* G' n3 I& @) w( ^, Y  f  e% A
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
1 ], D+ p& g, e3 Y

2 {4 G" Z8 V7 w( z1 _$ a
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
$ G: s1 x8 ?( ?, `$ O" U% C

& [4 u, M5 L% N, W) H9 H
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

- ^! l6 K& n3 q8 [6 l+ ~8 v
6 [( b, n' O. O# Y4 N% q$ c# a
输出如:
  1.         ' F* k6 a- _  O6 V
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码

- R1 x2 u: u  F. c9 j: O& c$ e
! Y, R  N+ i% w& w, k7 l) w# T. h- Y5 n: {
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"& T  h, P" c  u0 N! i- n" n
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance", k1 G* b0 L0 `& _6 Q* n9 r
  3.        xmlns:context="http://www.springframework.org/schema/context"
    2 L$ k$ A; k8 ?* e8 N) e! _
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    $ l5 k8 e& T' h- q- K  a
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    7 P/ j6 F& n* X6 I
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd) m) k* o1 ]! q# g/ x
  7.           http://www.springframework.org/schema/context: @3 @7 J6 J9 \- R
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd4 J; W& m5 T4 M0 s" t
  9.           http://www.springframework.org/schema/data/mongo
    & [8 B) D. T$ p0 n" }1 t
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">1 y1 K/ E8 l: A$ p6 a

  11. 4 P, q: c- @, n  y
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    7 _7 m8 v: ^0 ?6 G+ n: R5 V& }- q
  13. $ w0 m( K7 u# p" X
  14.     <!-- Default bean name is 'mongo' -->- _  {9 Z+ ^/ N/ K# p4 }
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    : m  [' t2 ?7 q, o; L" w

  16. 8 h2 g2 ^  {& @9 ]/ ~1 @  {! H
  17.     <mongo:db-factory id="mongoDbFactory"
    + J& j; _& {4 r  `. ~
  18.                   mongo-ref="mongo"
    7 T% `3 H4 @. K8 v
  19.                   dbname="mongotest" />  V9 T" q7 J# @& Y" N
  20. 2 w. S. q6 I: s; I/ q0 |
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    & B, d- G; O& a+ K' J- j! y* O
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    8 J  b1 m) H2 ]" p; f6 @! V6 _6 C$ _
  23.     </bean>
    " d1 S: J1 u/ \. R
  24. </beans>
复制代码
' d8 S( p% d1 a
" K* m0 p' s5 r4 a! [
maxmin的测试
  1. @Test8 Z9 ~3 D4 L2 |
  2.     public void testMaxAndMinAge() throws Exception {
    2 R* \3 o/ F( F0 k& _6 I
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);( T1 U  \8 r4 H3 V* ]& S8 ]/ O  ~8 ~
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    ! E' H6 Z0 W2 B5 z6 n2 s' J8 q" R
  5.         log.info(result);% W2 _" e# c. ]; }, G, f4 A$ L

  6. * C3 ]& m0 g4 v+ d5 V# q( m2 j) y- O
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    ; b9 w+ x( \$ w& W/ N
  8.         result = mongoTemplate.findOne(q, Person.class);& ]  ^. N6 p# }% l2 x7 |
  9.         log.info(result);8 z) _) t3 V$ j- Z% |* b  ^9 w
  10.     }
复制代码

  \3 i( b  Y0 F  B5 c; N6 j/ {/ _! ~
distinct的测试:
  1. @Test
      n4 h! U4 \% Z9 g7 H  U% ]% |
  2.     public void testDistinct() throws Exception {
    1 V) `8 ?0 c$ g" |
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    . c2 }# {5 Y) z3 p/ E
  4.         for (Object o : result) {  ^. y) W$ H. W! ~
  5.             log.info(o);
    * o) L: ?2 K" V/ x' k/ {4 b2 {
  6.         }! m- C+ X% J, Y  N; p) i* \# d# H. n

  7. & J. O8 X9 j- Z' E2 m, ^, Q
  8.         log.info("==================================================================");; Z) K9 S3 ^( s3 x% @
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));$ S# j- v; Q, N
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    . H& \$ m+ `, Y0 |$ U' l' i
  11.         for (Object o : result) {
    ) b9 O, d4 l! s1 @
  12.             log.info(o);$ `: x, j7 t+ S0 y% ?
  13.         }0 S( P+ T7 s, W* R
  14. 3 q5 ?1 D! G8 R5 V
  15.         log.info("==================================================================");$ U/ Z# h5 K4 q
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    ( I0 V+ I8 I: L
  17.         for (Object o : result) {* F- K5 M2 b# `, M4 p
  18.             log.info(o);
    # {$ s/ W. [# z; u3 Y/ t+ T
  19.         }) k& @/ K& _: R, d" y! q7 Z; T
  20.     }
复制代码
( Z+ _7 [0 s* C. A

7 m0 J2 \3 `/ e& g/ w
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567( y$ B4 H8 |  t% J$ p
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    ! d4 H/ v# _) ?! x- ^
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    7 a4 U- ~8 D4 o& c; g3 i
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876544 b# [! r" Q" k6 K
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni. J* P' J  e- U2 x# y6 i* G
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo) q9 Y# K. G' Y( Z3 k; M
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456' ~) E3 ^2 g3 \% }
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    # i8 M& k( \0 v/ M, _& V
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    ' S- ^2 g6 m5 l; X! m1 i8 \
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    0 i9 x; r9 ~) ], {+ p; P0 P4 x4 A# w
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567892 o# c: D, C9 b9 \; g- C/ O
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876542 r; [) `& U' \
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    4 h9 \* `- U. D- y  t6 f# [
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    / B3 W4 X) W  B
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    7 d1 u9 d* H" I2 }
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc+ m4 e0 }7 E- j, S8 t
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    8 y8 Y5 n$ u! Q
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx  V! c5 B6 `/ K5 d
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy
    1 v" ?, Y3 `; v6 O; m! P
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    9 V6 w9 |2 C4 S: b' a
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    * p0 `, v; k$ Y( c" W. y- `
  22. 12-22 14:13:45 [INFO] [support.GenericApplicationContext(1020)] Closing org.springframework.context.support.GenericApplicationContext@1e0a91ff: startup date [Sat Dec 22 14:13:44 CST 2012]; root of context hierarchy
复制代码

7 e  p/ j- W( x
7 A! S5 E) y4 S* X* ?  e+ G; Z$ d1 h
这里我要特别说明一下, 当使用了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等信息。

) ~* t) R. ~# f3 i6 T' X5 [
- l# e- D5 X# I2 z
! H8 S4 f/ A+ w+ z/ J6 p2 q* _




欢迎光临 cncml手绘网 (http://bbs.cncml.com/) Powered by Discuz! X3.2