cncml手绘网

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

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:# O) |: E  y( w# f9 b7 o: G# s

, L" B- }& A: E0 ^9 O1 ) . 大于,小于,大于或等于,小于或等于" ^: i/ ?8 ^5 X: k
, C9 U4 J, i% f' o: E
$gt:大于" t& O* ?6 r2 `0 ^
$lt:小于$ c& V2 X( D! v( n
$gte:大于或等于
; T) ]* w) g. {# B( f5 }6 [$lte:小于或等于
$ h8 j+ s, l% G( h
  s( |: s" S7 K2 v. r例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value' ?+ d" P1 d% {& k
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    # I* M# |, f6 W' E& C
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    ! e" |( B/ |. ]8 m2 D% i. |
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码
8 R1 i2 F3 b) O5 E. I5 Z$ b
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});  G4 a5 \0 s# O# a) J1 {7 F* D
  2. db.things.find({j : {$gte: 4}});
复制代码

, m- u, E* e5 e: B" @5 w! |. t2 i
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

- O1 u: x7 o& _, x8 w6 `) O' a) Q& `! ]+ H) j- j
7 m8 ^# }4 \' U  ?/ U3 p6 M
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

, }! L% h3 w5 t( y) D' L
3) in 和 not in ($in $nin)
) g: O5 N4 i% C9 Q& C4 B$ G3 q5 @; G; n* G3 Z) j2 S7 n
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

4 Z2 K3 R& \/ ^2 F$ w9 M
例子:
  1. db.things.find({j:{$in: [2,4,6]}});4 W! V* ]/ q! G, V/ z
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
2 G9 g0 r/ ^4 C7 ~) |& |. i

' P8 Y" w" d) ?. @% ]+ u+ p4) 取模运算$mod
+ `; p4 k3 O9 n/ j/ B4 A4 M* |
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
0 i  j% P8 D7 i
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

4 j. H1 i" m- [1 P2 S
) w  j4 F7 s  E% w
5)  $all
# j% b: b4 p* X" G9 d7 c, t0 J- i9 A/ M7 h# ]
$all和$in类似,但是他需要匹配条件内所有的值:
2 K, f4 ?* E8 e9 Z( ~4 c# ~0 y# N7 q4 L' c1 y! X0 `
如有一个对象:
( j: y+ [4 Y% V! u+ Q
  1. { a: [ 1, 2, 3 ] }
复制代码
! o7 F8 t) [- j! v9 z' ]+ Y
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
( V8 G/ ^: L  }
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
# C6 d9 U8 f. P& l( ~
) `, v4 A9 A7 S1 t3 N9 v
6)  $size" C) C5 h- S9 m  f# H! J

& G, c5 M; X. {+ F; h+ c$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:" u! l1 B7 e9 n) G3 l6 z

- I+ N( Q; \! w4 `下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

' V  K' ]4 T9 P6 t
官网上说不能用来匹配一个范围内的元素,如果想找$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.
- f( V! C: M* Z! Z7 R; g
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回
    . d' p9 A" }9 _( g( K: Z/ }0 B+ P
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

. r3 N6 e/ @9 ^$ A9 y
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string
    0 |8 G* ~% [# f' V, x% w. ^
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

9 e/ a' p3 L8 C1 y7 e- p
9)正则表达式
: H1 k6 i5 y& L9 z1 p% K: \' W8 I: f& W
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

9 c8 e) D, h% ?9 l1 |0 H0 }
10)  查询数据内的值" [, ]; G5 N) t

& ^/ E# T- G) A7 |7 ~# \; G下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
5 D9 T0 p( w/ _
11) $elemMatch
' @0 D$ U/ Y' L( s/ |
- w2 U; I) b8 R2 D% }1 M5 a如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } )
    ; ?5 Z5 x& V  G
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  ' t8 B- a! @1 }; z8 z: T+ A& W
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
      g6 K; z$ P, W* P8 v7 T
  4. }
复制代码
# a* R' h& D$ `5 g; E7 L
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )$ e  s. H% p) C" ^# c
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } 5 `2 ^0 o) E, v7 a5 k' b

: U. [: J6 w8 ]  b12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
. f$ z: W7 e8 ~% _- P: f2 q
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

% _4 y4 f7 D1 d% w
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

1 Y9 X9 {$ q* D( A' V8 s( \) I/ h
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
. G  x3 m" Z* J$ ^' H/ H/ P" b
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
  g; }, O5 v4 Y; x! b4 R1 g
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

0 T& ]% t; Z9 F) S% Z1 A
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    7 [+ q$ v; w6 o( O. R; a
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

' k+ N7 e2 A+ _* Z
mongodb还有很多函数可以用,如排序,统计等,请参考原文。: v9 n- I# b1 Y1 c# i$ X9 A
1 x3 x2 G8 T& G
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
# J# Z& t; E* B0 f2 W
# h! ?6 c6 g4 l" \) l2 Vhttp://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
$ A& n6 U( W% a' m" V. |
, U% a: G/ t# N  ^' x& t0 W版本二:
* w4 x; @- R/ f4 ?" z
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
1 q# q  v9 c4 [' \9 W
  1. use admin
复制代码

) V) k: P( x% v+ q/ N. ]- u
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
- t' d( ?" |9 I" N; j: N/ i3 l1 w- S! a
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

  s9 I: n: K- M+ U: T! j4 k
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
+ N+ y; b5 Q( [8 B( `/ r
         5. #删除用户
  1.           db.removeUser('name')
复制代码
3 z0 L7 u; n# q' U* W. l( |4 k8 w
         6. #查看所有用户
  1.           show users
复制代码

! Q- j& K3 h! ~0 h" |! S  T
         7. #查看所有数据库
  1.           show dbs
复制代码
: O& e0 [# u2 \9 V. M
         8. #查看所有的collection
  1.           show collections
复制代码

0 `$ s7 B. f' u- a
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

; l5 f: X# C- P/ ^" [' w) s2 ?
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
" w" g$ R2 r  Y' `6 e7 G1 q
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

9 a9 o& h  Q2 [- R0 z
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
5 K: H. z; j$ c
        13. #查看profiling
  1.           show profile
复制代码
# R/ Q% Q0 S$ E" v) A8 ~7 o
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
1 u9 g+ ]5 w2 ^9 E4 o; O: i
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
# g* m/ A4 d5 I7 }3 u
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

, T" I) _: N& `7 ]" k9 a. I5 i, x
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
+ x$ O/ r' E1 L( P
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码
5 x& g0 Y( h9 P
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
: R' s) s% C; m8 o' n, j: G5 u
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

/ f0 C' x  X4 G6 m% ~( L  I
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

8 |1 _* @! M; a$ q" T/ F
   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()
. Z; E7 b8 Z4 C1 q( w5 v7 z; n+ k
6.  高级查询
条件操作符 / o" B& e3 P$ q8 p1 {9 q4 j
  1. $gt : >
    ! A7 x2 s  {5 |# \# ~9 X3 b
  2. $lt : <
    , w: o* f' l1 e6 u+ u! u" c
  3. $gte: >= . |" Y: U$ h, E
  4. $lte: <= 0 N' g" X( ~6 _5 V' D
  5. $ne : !=、<>
    9 a- D. C1 R* s1 Y8 a/ t3 S2 D
  6. $in : in 1 u9 I- z" J/ a3 M2 |2 F+ X
  7. $nin: not in
    ; u! N3 W/ {  j& P8 w4 ~
  8. $all: all
    " W8 {8 M; g- C  ?
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

1 C+ v) r6 J6 b8 F$ s: i& P% x: p6 a5 a
查询 name <> "bruce" and age >= 18 的数据 ' X5 j$ A$ v3 B1 I: _
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码

/ k$ n7 x6 S* B1 Q% A4 x# e/ Q
' ~0 T& `' M( N1 b1 z查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
, E0 g1 B  @) [5 R+ m' k
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

) H1 p3 |+ I2 q* k3 }$ u+ o* w1 t* E0 w& G: S" }$ U
查询 age in (20,22,24,26) 的数据 # ^# ?1 W  b# ^9 t6 U
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码

! S/ c# Y( }6 K- `4 F
* e$ H$ e+ m- ?& P' V- p5 w  n8 }查询 age取模10等于0 的数据
% \4 m7 ]" P. m* F6 }
  1. db.users.find('this.age % 10 == 0');
复制代码
% @% p# I! P+ y+ J  e8 A8 P4 S
或者 6 z# o; q1 c$ g6 h9 A& E0 U
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

! t$ q1 _" F% h* F0 N1 y, t* q; C1 T' \* b: D6 z% r
匹配所有 : ?, ?- S4 u: l
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

# j6 J3 j" l$ I可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
6 m$ y* |$ d7 j# m- p可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } " q& j/ Z% ]5 A6 n' A

; W( f* O) M5 v0 n& S' p7 D查询不匹配name=B*带头的记录
. @9 G5 |1 ^4 ^6 g
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
, g: I5 p" U+ M
查询 age取模10不等于0 的数据 ' }" |6 S. t, K) @
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
& h5 E: J% J& P+ p9 |* E

2 j: N% @  e0 U) v; b1 [) s#返回部分字段 4 `+ K/ T  V4 ]* b
选择返回age和_id字段(_id字段总是会被返回)
: o8 E* O+ [; X1 y4 {& s
  1. db.users.find({}, {age:1});
    / h2 m+ D3 ]# X/ M6 Q
  2. db.users.find({}, {age:3});
    & O& A+ m2 x: n2 w; V1 C4 \
  3. db.users.find({}, {age:true}); . F* z6 I( z% X- w; m
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
" J* d* E% w" w1 Z
0为false, 非0为true + z' `; G) y6 K: L

3 b; [. y9 |  j* L' j5 T* ]选择返回age、address和_id字段
* F) R) k1 h  a; N* n
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
1 H2 j( \. K& \4 |

0 x' C0 t3 U  }5 v, j. {排除返回age、address和_id字段
+ ~8 s: Z9 R: W
  1. db.users.find({}, {age:0, address:false});
    / }* h# f8 y6 L7 j7 a
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

5 x* q$ ?' R. k' P: f! D! n, I$ }/ q; F0 n. t6 B9 X
数组元素个数判断 9 k7 c4 m8 B, N# ]3 J# H
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
8 ~1 I2 y$ f" E6 n. g6 l1 \匹配db.users.find({favorite_number: {$size: 3}}); : d6 p) J/ x  k0 u) e+ _
不匹配db.users.find({favorite_number: {$size: 2}}); % P- l8 |2 Q( n, {, P

: s& b# y; ~! ^- g$ D3 t7 X$exists判断字段是否存在 : A7 n, w. H3 L! N
查询所有存在name字段的记录
$ F6 L' h- h. _" u1 Y/ |
  1. db.users.find({name: {$exists: true}});
复制代码
9 D5 `  J0 G" @
查询所有不存在phone字段的记录
- Z& L5 e5 a+ \1 I8 i4 }% R
  1. db.users.find({phone: {$exists: false}});
复制代码
# q( ?' }6 }0 ]8 J% F

# v  z  u, d6 @& Q$type判断字段类型
3 q' {. O9 X$ A/ E9 |查询所有name字段是字符类型的 ( V5 i+ ~% K) Y1 s3 N7 W
  1. db.users.find({name: {$type: 2}}); . s& j1 r2 h3 I( K7 q( l
复制代码
: D7 A! Y4 k$ O) l
查询所有age字段是整型的 ! [$ Y& D9 M3 N& V
  1. db.users.find({age: {$type: 16}}); 1 ?4 |+ O5 B% Z4 c* {$ M6 ]
复制代码
/ ]! W" Y3 X% C" [9 ?  f
对于字符字段,可以使用正则表达式
8 O& v" V( @9 C3 R$ {查询以字母b或者B带头的所有记录 % ~( Q- H1 ~6 @1 t- b( F: D
  1. db.users.find({name: /^b.*/i}); 2 u/ n7 v! V9 @1 b6 S! ~
复制代码

. K9 C+ D8 N' U2 h8 m% F$elemMatch(1.3.1及以上版本) + M5 I- t$ b; x  ^
为数组的字段中匹配其中某个元素
# L, b+ [2 P/ F' |# ]' S+ J  W
0 Q8 i6 `* F/ ZJavascript查询和$where查询 & U) l/ r0 R9 ]2 |5 e. w( D- ~
查询 age > 18 的记录,以下查询都一样 8 n! P& I7 H0 [/ P4 G4 n( x
  1. db.users.find({age: {$gt: 18}});
    0 Q# ?! {( M# v, C! h  p5 z
  2. db.users.find({$where: "this.age > 18"});
    ' I& }+ t- c& P. N" i% z  f# i3 M
  3. db.users.find("this.age > 18");
    2 Y0 ^: X/ ]" P8 R: o
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

7 O7 M4 \7 w, z+ w5 H3 I+ v$ _( ?$ g! u7 g* o( q
排序sort() % d9 X& b, U9 P
以年龄升序asc
8 o0 }- ^8 M& a% [5 f6 h7 }' o1 C0 o2 ~
  1. db.users.find().sort({age: 1}); $ u$ Z. y8 l1 |6 y3 [+ p2 U
复制代码
1 _) Q8 D: ]9 L7 e8 j# @2 c
以年龄降序desc - D4 H) ~' c# F: W
  1. db.users.find().sort({age: -1});
    : Q% H8 m  H0 C: o! H9 S
复制代码

2 b4 M$ V. _: H2 @: d限制返回记录数量limit()
  |+ K  U8 p- \5 X. Q0 S2 X7 {返回5条记录
$ C7 X; j/ W0 U) N
  1. db.users.find().limit(5);
    & u9 o8 E- [, W
复制代码

- E& v/ {7 v! m: o8 U返回3条记录并打印信息
$ ]3 \" ~6 v4 {
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); / s  m) l- `! [4 X) B6 u: u7 m
复制代码
  V, e5 W& c4 s8 Z
结果 # l% I; R! z1 p& z
  1. my age is 18
    " F. n" D/ r9 O& T$ B
  2. my age is 19
    1 X+ i( o5 Z3 w0 D0 E% s6 A
  3. my age is 20
复制代码

- ~2 c! W. ]9 @* K! _- G" t
. q4 d' k0 G( E限制返回记录的开始点skip() 1 y4 [( r+ Y% V/ @# `7 f* w
从第3条记录开始,返回5条记录(limit 3, 5)
# Q- Z8 q. v# m. n, c7 ~
  1. db.users.find().skip(3).limit(5);
      `: {9 ]2 U6 W: q2 @" a9 o* {2 f* x
复制代码
3 l1 H4 K2 v( |4 }
查询记录条数count()
, p2 S3 Q" {3 J+ \* J- sdb.users.find().count();
$ D1 \/ G# g4 r5 f7 \# qdb.users.find({age:18}).count(); 1 ~/ f) m0 i9 i* y2 _- O) b& p
以下返回的不是5,而是user表中所有的记录数量 4 z! g/ d" O  x, D
db.users.find().skip(10).limit(5).count();
) k2 N6 w, [' ]7 l& m5 R8 N8 Z如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
" i; F( \: z2 W. G
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

& m4 e; z( x$ n5 Q, `9 a3 E4 V/ }; N3 e! O; K" v8 g, d
分组group() 7 [. q+ w* `3 Q$ }6 C
假设test表只有以下一条数据 . D7 }# U4 E" I) E& G1 ]1 J) Z
  1. { domain: "www.mongodb.org"
    ! c8 z) \* P  u' ?1 K7 ~5 O
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} . j# }6 H" g5 M3 p0 p  S9 z/ @
  3. , response_time: 0.05
    5 _$ _, a. z' C7 b" g) `
  4. , http_action: "GET /display/DOCS/Aggregation" , }1 \1 [! ?4 e8 t
  5. }
复制代码
3 ]  I) |9 t2 S, u* I$ e" O2 C
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
, j6 W3 i" E0 d, Z- F3 `" J% [
  1. db.test.group( ) V1 R, S6 G* U& k$ w8 S
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    ) v; ]0 H/ F7 N1 L7 W( L6 A
  3. , key: {http_action: true} , z" n3 G& R% m9 t7 }* |1 z9 _5 [
  4. , initial: {count: 0, total_time:0}
    / p0 q) P' g- C5 G% i
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    2 H! p; _- t' |& |% @" W, l) L! _
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } % x, m( ~- O4 w3 q( O- C! E
  7. } );
    - ~! z3 w9 k+ `/ i$ w
  8. 3 S2 p+ u( \: j/ }4 {- }
  9. [ 0 q4 O. O) f# L( g
  10. { ) e: U) h$ _7 O/ n; Z4 g
  11. "http_action" : "GET /display/DOCS/Aggregation",
    ! ]3 v& ^* ]: Q2 T; H+ P, D+ u+ c
  12. "count" : 1, 7 v) I: O. g; V2 e+ T( E
  13. "total_time" : 0.05, $ W! h3 G8 ?7 ~; I
  14. "avg_time" : 0.05
    9 _2 c% [' s, h& q* ^  p& f2 l
  15. }
    1 P% W% |3 p1 E& Z+ u
  16. ]
复制代码

. E( X, p0 ?8 }, ^! ?' z' H/ g; p/ ?9 Q& N% w

) T' |' x& d5 Z6 a9 t% }( V0 ZMongoDB 高级聚合查询
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
    ; Y+ L- }, Z7 t6 ]/ a; A$ ]
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
: m/ E  i) ~, E4 F$ b) e
/ u0 U" M# Q4 T8 _
3 v3 R/ B* d5 g+ u" y
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
- K. m/ n7 g% f/ O9 M  r6 |, Y* {
+ |4 u' P- C# j( H% f
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
- v7 \) e& ]* u2 S0 P
. k, l. S0 z) M1 J( q
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

' M, ?9 C6 T- H. t5 B2 k: F9 V8 T
) v  g3 {0 |, u
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码

- s% d! w( k- X
# W7 ^  o! U& j2 \4 f# o; P" R; H
输出如:
  1.         4 X! h/ C# V. F0 s. q1 k% f
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
" I+ s  B( d9 V5 m4 ~  d7 r
, ^2 w( p" M! J! A2 B

- O/ @& c7 r0 P( w3 h' {8 E. g5 |: `
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"& @0 c/ @# p2 j, @
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    0 i, Q( u$ j: U( l* ^
  3.        xmlns:context="http://www.springframework.org/schema/context"
    3 o  P- v1 J* T
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    # `& a% H5 M( t0 s# O1 x8 x: L
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans& t- u5 S6 k  |7 Q
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    ! v  _: r# }4 ~
  7.           http://www.springframework.org/schema/context
    : K9 \7 _( M* g; ~: n9 e# ^# w. G
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd
    : h" z1 d- h3 f0 @$ f# _
  9.           http://www.springframework.org/schema/data/mongo* s' u) Y% j5 g
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    9 F  M  z0 J, g0 n2 p$ ~1 g9 s
  11.   M$ p8 H3 {0 g
  12.     <context:property-placeholder location="classpath:mongo.properties" />& I  I0 t/ g( t" X. l1 G8 q
  13. ; R. v0 n( \3 {7 G
  14.     <!-- Default bean name is 'mongo' -->8 F, D/ @" I/ q2 S
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />+ j8 k; t) ~2 t" W! v3 L

  16. 6 M6 }3 d" w% |% o! v$ p
  17.     <mongo:db-factory id="mongoDbFactory"
      s2 G9 I! U5 ?
  18.                   mongo-ref="mongo"/ e  G5 V4 l  v: W, c
  19.                   dbname="mongotest" />
    $ \4 X7 e) N8 s- G  J

  20. : a' s5 l0 q, G2 k  W4 |8 P5 m
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">3 D2 v3 Z- z0 X1 V
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    " M( B2 \/ }& N' Q9 H! q
  23.     </bean>
    , E$ t) P# h$ X3 w7 b
  24. </beans>
复制代码
8 \6 |- _; E  T- B( F  v% J. p4 a/ g

7 G; _9 g" J% ]" Y) z2 P( m
maxmin的测试
  1. @Test  J! k$ A& l0 R3 O: q
  2.     public void testMaxAndMinAge() throws Exception {
    ' f7 r/ w4 U5 m, N( Z2 \5 E
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);. J- y: t9 R. @# W
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    9 U+ S: b- f' S1 z) N# }# g
  5.         log.info(result);, e0 l/ x9 A4 ^
  6. 2 b" D% U9 T8 l4 ]5 H
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    . W( K6 `' ]( _% H9 }5 J
  8.         result = mongoTemplate.findOne(q, Person.class);% f2 O" v. F7 ~: i0 u* K
  9.         log.info(result);
    % K6 {. N; h& r0 [: H6 w  t2 P
  10.     }
复制代码
9 z2 O2 E3 `0 ]* g3 d
3 i7 Y  \$ z2 V8 X$ C& U
distinct的测试:
  1. @Test6 V# U, W9 O5 N* L) ^: H+ f; v5 e
  2.     public void testDistinct() throws Exception {7 e* P3 |5 Y- t! k9 U; R
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ( k  N4 B6 i4 d+ q. K/ M& Q6 ]4 j8 R1 N
  4.         for (Object o : result) {
    7 y1 J9 E9 U) G% v! x0 k
  5.             log.info(o);* M/ e' l3 |  T* n
  6.         }
    - m! a& f1 ~6 E$ e/ D

  7. " ?) M' H4 I& B
  8.         log.info("==================================================================");
    & ^) e7 K+ s' R* e! l6 x
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    ) }# s4 L2 X! F
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    # t) z+ h* o) P' O1 E5 U
  11.         for (Object o : result) {/ E, w9 [) x, \5 H6 ^' n! v( f
  12.             log.info(o);; l& P3 s: m1 n: }; f
  13.         }
    $ j' s% Y1 B0 L; V

  14. - b& v% O5 [9 G: s/ T+ n
  15.         log.info("==================================================================");9 U# G, o# [- n2 g7 J$ v* d
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");0 r7 ?1 Q' q# M1 `) g  J
  17.         for (Object o : result) {' g4 C2 {, M2 j0 A
  18.             log.info(o);
    . K  i: y7 C6 s
  19.         }
    ( E* C3 b4 l; E0 {, n9 T
  20.     }
复制代码
* @3 R% V7 F* k. a" h) n7 t  ^6 e
' M/ d+ ]+ x- S+ e3 B
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    8 m% W! Z. ~1 `; q  V. c) t
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678" `, |" }% ?# w# }
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
      |( p; c( @3 Z0 h1 a2 E& ?! d6 F
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654
    6 x" D2 W4 \7 {3 R$ B% H4 Y
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni: e# J( I; e. o5 o
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    ( }& D4 I9 S$ ], W$ @3 j
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    ' N# k& i' d$ d+ d( k( C
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================
    ! K8 ?- @3 {! U1 h$ T
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567) c9 [, J, X; M; z9 a6 O! r0 e
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    9 z  W7 Y" n5 V$ ^+ ~
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789
    / U: _2 T. b' N8 c0 L3 }
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    $ D7 R+ |! Z- K; ^
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================0 H, A4 G0 S# u
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    ; O, A  p  Z' g" @" X3 y+ R. N- r1 u2 o
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb
    : j5 I& E. C; X' a- m& E; ]. `
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc! `2 N" J7 {( G% s& v
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www" s* M% P3 o8 f- h! o( y3 s
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx; a  D: B" ?6 s( Z
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy/ A: D/ R$ t7 E- A
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz1 A" q: J1 c9 z* m1 ]( p5 _3 @
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    9 G0 X* b! Q( c
  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
复制代码
4 V0 `, c2 b+ ?; Q" U
; M1 q) X$ 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等信息。
$ F2 |* V! s' d+ E

  G6 A* S. @$ L. X7 i( l" k, d8 U8 V5 m- c+ T





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