cncml手绘网

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

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:7 o* |; g( E2 J0 ^

4 N9 w# u( {+ N/ E5 }1 ) . 大于,小于,大于或等于,小于或等于
+ r: [9 T8 A+ G2 I" r$ g
9 @6 z  o9 ^& v' p2 U. H3 T$gt:大于1 R# u# G7 b; j( f# x8 g$ v
$lt:小于4 y  ?; B1 l9 q$ @
$gte:大于或等于7 D+ K9 S! _0 O$ F  ~
$lte:小于或等于
' b# V5 ^6 b1 {8 d% d5 C/ |
" y" l3 x8 G) Q! L, v  X5 v例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
      ]3 c$ R/ x8 k( [$ \
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value
    & j9 }' m$ z$ t
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    0 p" M2 F" y+ f+ w% X8 D
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

: L; t  u9 E( D
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    / b6 {& |7 h3 x+ b
  2. db.things.find({j : {$gte: 4}});
复制代码

0 G, Y3 a& o7 I: h8 K
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
! m  C* X6 S& p- U$ w, L, s& _
* n% L" f' H1 ]' S) P# I, e

4 l) ~; h/ ^- K9 C/ l) u2 L$ t
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
4 t2 C5 R/ I  ~) G; B3 Z  w
3) in 和 not in ($in $nin)
) g, I8 [! [* u" U" @
' ^. I2 Z' @) u; H) D语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

7 i& X& c+ B6 u! c
例子:
  1. db.things.find({j:{$in: [2,4,6]}});0 C' p2 k* @: D
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
  e3 Z, a  M+ T2 K0 k& o: q0 v

0 z' o7 a+ }; w* U' }! ]" H1 G6 d% t3 N4) 取模运算$mod  g3 e  i/ k- k- X; e
) O0 {2 Y, _4 u' d0 |' v- d
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码

7 V% X$ i8 K' Z! ?1 V
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
3 r( [$ e! v+ `9 D) b1 n& q
) D2 e1 t' _3 I. \$ p$ p% P9 D
5)  $all9 `. \' D( g* t+ ^$ w3 l. D5 V  k
3 s8 w6 F, l0 ]0 p
$all和$in类似,但是他需要匹配条件内所有的值:
2 y' N1 d( n. {$ q
3 T- Z* h7 A( k1 e. O. N( M如有一个对象:1 b& B6 E4 e2 P
  1. { a: [ 1, 2, 3 ] }
复制代码

6 a0 O" ?- s; k+ a
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
, H" f4 v2 k! }1 _8 W
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
( W+ t( k5 H% Z  m% }' S5 B

) i) \, g" e0 P% V- E8 ?% m2 _" e6)  $size6 ?! f  n" g. A3 U$ e; O
7 D  d" d/ u* ^
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
- B3 `- i0 }/ t( ]" o
# r4 X8 A5 C# _下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

( I5 ~3 a& W- ~1 Y& e2 ^
官网上说不能用来匹配一个范围内的元素,如果想找$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.
8 C9 N8 R6 l% f
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回5 K5 S: S5 z9 @) s
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码

# F9 F# y8 g  }) r
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string& q- o& I: r- }% e( V# C) n4 c2 H6 R" E
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

3 H% X$ s# E: ]) `
9)正则表达式
! u4 D) O" e" p5 W* X* }1 v. e; F9 A6 A6 P  P2 F
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

+ H0 b( a/ \* Q- n0 |1 G3 a
10)  查询数据内的值
/ l9 [& H2 ]3 d7 d* U$ l* y( x. c4 _6 ]8 [) T, J$ D
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码

/ W, Z: x6 w( t, {
11) $elemMatch
3 T; h7 x7 L7 C- `) ^( d2 D' f
  ?& v+ L& n3 n# u& u1 q如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 4 V& r9 U) b8 B& {2 B
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  ! }4 l/ u5 U5 k
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]
    . l0 V" O6 R& s4 U8 y
  4. }
复制代码

1 d9 O* u2 e% g+ V9 y# ]" s0 u$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )4 s  i0 W& p# D! n! S7 n: H7 U
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
; ?0 Y5 t4 y# h/ c% S+ U$ N( t4 f( @1 L& s9 u& N( p. A! R
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
) c, I; v% j5 Y8 d  X
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
) G- \! n0 q( @8 W
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
' G; a, L  l% x% T
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码
7 V7 S0 |  n* x" ~9 w# f: g/ H% ~
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
- z, m1 R* k9 x
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
! e$ ]' X# n4 q. u& _! i
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    8 Z2 w8 \3 W/ L# u
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码

  ~$ a+ `9 ~9 O& G- ^
mongodb还有很多函数可以用,如排序,统计等,请参考原文。; [# j5 q2 A- X3 U& m* Z
, Z# R4 |( z0 n# l
mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:+ Y9 @7 c$ L4 ]* s
4 o: k# n- |  d
http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions1 j% g7 ]8 P+ ?' D& n5 g9 t
0 L1 ]2 Z  q7 p0 r  m  F
版本二:2 D( l- A" `/ Q' `; _9 M0 a- |) h
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
% f/ V. w# D* l9 d7 b
  1. use admin
复制代码

4 z- p* R) Q1 u, K
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
/ A# I# l5 o4 _' @% {% V% _
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
$ J5 Z0 Q& B9 n# M9 @% T
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

1 `2 e2 x; q: ^1 d- C' o
         5. #删除用户
  1.           db.removeUser('name')
复制代码

, Z1 M8 h! ^* T. K& c! I% i
         6. #查看所有用户
  1.           show users
复制代码
) w/ Q/ a( v7 [& m
         7. #查看所有数据库
  1.           show dbs
复制代码

4 r; g/ y% p  w  t% |: e
         8. #查看所有的collection
  1.           show collections
复制代码

! X& @* D! ~8 T0 b# I5 Q5 I; c! d
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

& T6 L# x' R% r% B' Z; l
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

4 d  q" E7 f, u9 l
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

3 ?. W9 `, l. U& \0 o! c& @
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码
4 Q1 l3 X6 C5 c7 c2 s6 `+ _) A
        13. #查看profiling
  1.           show profile
复制代码
* L; h8 S3 n, l% {. E
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
% O/ h' x4 A4 w5 B
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
( T( K% M; M$ [2 C
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码
! o4 F+ T9 L1 \2 {
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

# y& Y" y1 @; J* J) g
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

8 d$ L0 q2 g+ X& \- C$ c% a
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
8 ^, X9 h- @: g! n
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

4 H, G1 @/ c, B" Y7 x  y; D3 B
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
2 {( G2 R# o& z4 m3 a8 G
   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& h3 M/ |6 O9 X. F
6.  高级查询
条件操作符
/ w( g) a1 y9 S  x
  1. $gt : >
    / ^4 i' f+ z9 \
  2. $lt : < & v2 S+ A+ k" H" u
  3. $gte: >= * h- D% W4 C+ d+ t' V
  4. $lte: <= 8 |; f* R& w1 z8 }5 A; @
  5. $ne : !=、<>   J; F2 z* u5 `( g% S) H
  6. $in : in 2 {: U( a5 o- }3 X6 H
  7. $nin: not in 9 q* h% }$ u* b) h4 D
  8. $all: all
    . K! c& Y  S( l0 Q/ q
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

8 X& k) O6 j) ]# a* N6 e9 D! a' T" k" O- E8 |7 l
查询 name <> "bruce" and age >= 18 的数据 ) H3 N: Z- B% q/ g5 L9 i: v
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
  S, m* [, ]  O$ _( f- |9 x

2 O" H4 b; m8 s8 R查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 & @9 I5 _$ l& }. y* @. K$ E+ V: `
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

0 t& A8 Z8 p1 R: {9 O( q7 D% I* ~; v4 A( e( x5 d5 `# H/ Z# g3 v$ l
查询 age in (20,22,24,26) 的数据
( F3 S6 k& L* x
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
# }, w8 ?# w: u6 J* y" z
, \& Z7 |8 o  m8 A2 u; _
查询 age取模10等于0 的数据 " c6 P: I$ }  L
  1. db.users.find('this.age % 10 == 0');
复制代码
. h4 x) Y4 M8 r! Q
或者
  L: }7 z0 I: ]! H8 v, l* [
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
; ], r% |5 ^( _3 E) Y' n' R/ ]7 `

* @8 I1 X; p, i5 w( I* d匹配所有 # W9 S+ I! X0 ?$ o
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
3 m0 K9 M' T- p5 ?5 z6 _. \
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
8 L# w) t2 ~( K8 K( E6 v可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } + \0 t& ~) s% c, ~5 @8 G

2 F" c( {5 E: b: _8 k+ g' x查询不匹配name=B*带头的记录 ; R9 h: Q- s/ R/ q2 ~
  1. db.users.find({name: {$not: /^B.*/}});
复制代码
& U6 Z% P0 o0 ]3 H9 X& q
查询 age取模10不等于0 的数据 5 l  d6 A6 S+ ^  k: J) i$ P
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
1 Z3 w$ `% a* p) Z/ ?& k
! w7 d: I# K. q' B. M' Q  ]2 K
#返回部分字段 1 E( R+ n) f  A. p- S  i
选择返回age和_id字段(_id字段总是会被返回)
7 w" s. e" N5 p' y: [  T# d; J' t
  1. db.users.find({}, {age:1});
    ' ^( X3 z$ e1 h: n9 M( [0 b5 Y
  2. db.users.find({}, {age:3});
    . W8 c  v# {" d- |/ h9 \, n4 n. ?
  3. db.users.find({}, {age:true});
    8 d( p: [$ ?: g
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

7 Q+ i1 B* Y' p7 W) `0为false, 非0为true
  c& a8 W! }' c3 ]* [7 A1 J5 \5 }3 s! S; L( q* J- r7 S
选择返回age、address和_id字段 ! m0 i2 U7 _: `( [* N" g9 M, j
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

9 b0 p  W$ u" F
  p) y+ s! |! ^1 K8 ]+ K排除返回age、address和_id字段 / X  X# X* l% M& T* z% ~+ W
  1. db.users.find({}, {age:0, address:false});
    0 g+ `) n( ]5 {) M2 f# B3 D5 t; V
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

, n; `! J& o  M
$ X: u# H; A, b4 A; t数组元素个数判断
( O! p9 J( \, U7 J4 U对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 ) j5 `7 N1 e2 T1 r, Y
匹配db.users.find({favorite_number: {$size: 3}}); 1 s2 x. i1 c* `$ p
不匹配db.users.find({favorite_number: {$size: 2}});
) ]8 s# r1 D2 F9 c, k% a: P: N2 S- l- D1 J8 m3 Z
$exists判断字段是否存在
) J9 W4 Q  }; r1 K9 y( }查询所有存在name字段的记录
3 ]0 z. \/ s( F2 r1 t" j& r7 J
  1. db.users.find({name: {$exists: true}});
复制代码

# b  x' }7 n8 i0 w) ^7 R5 i: j# @5 u8 S1 H查询所有不存在phone字段的记录 ( _5 `6 w& f7 [' W
  1. db.users.find({phone: {$exists: false}});
复制代码

* F; W; k( }+ ?' J. p( f& O- F2 N$ q/ T, \3 [" G
$type判断字段类型
7 G# {. j  l% V( Y查询所有name字段是字符类型的 , l- j* o3 R1 w) [! }$ ]. l
  1. db.users.find({name: {$type: 2}}); # b1 x/ K" M' S% b; U9 |
复制代码

4 z, r% V. ]0 c0 M9 w查询所有age字段是整型的 * f5 @. c5 {7 `6 a
  1. db.users.find({age: {$type: 16}});
    ' V) s* M3 I0 S6 r
复制代码

7 t6 Z9 |& @! w5 U对于字符字段,可以使用正则表达式 + X2 b1 l/ Q8 I
查询以字母b或者B带头的所有记录 2 B# G1 a! }) u( N8 S  {7 R
  1. db.users.find({name: /^b.*/i});
    4 ]) F9 p# C1 S+ E+ L, {
复制代码

# x5 b' `* U. u: n) v$elemMatch(1.3.1及以上版本)
5 u1 v; p+ }5 E为数组的字段中匹配其中某个元素 ' S1 d1 O! O, p0 [' d0 u5 p9 B

. o1 G2 j4 P; T  a. BJavascript查询和$where查询
( T4 L# \4 f( s3 E/ M* p: H查询 age > 18 的记录,以下查询都一样 % i% V1 G5 M( l" k* n
  1. db.users.find({age: {$gt: 18}});
    % `% V; y1 c8 }7 P5 r( E/ C
  2. db.users.find({$where: "this.age > 18"}); " m. u/ ^1 x6 N0 t. x' P
  3. db.users.find("this.age > 18"); ) j# p4 M- C* |3 W  J& v
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

1 J0 y2 F% [. {7 P! g& c4 H4 {  [5 |5 k8 q: n
排序sort() 1 M: G2 U8 L( H" ^
以年龄升序asc 4 b& m0 l; {3 g( e7 Z
  1. db.users.find().sort({age: 1}); : \  }- E4 c3 h5 |, S. `$ j9 {
复制代码

7 T+ H7 G- h0 b: d% q以年龄降序desc
! t4 a/ d( |" p' @3 R* x  g
  1. db.users.find().sort({age: -1});
    ) p6 q5 n! m; _# s1 h
复制代码
3 X7 k& A- v# s9 E# k
限制返回记录数量limit()
0 Q/ {3 P* H( J8 i& Z$ u返回5条记录
4 x: u" _8 P2 s- n) `7 i% H
  1. db.users.find().limit(5);
    9 w) K2 n& U2 y2 o# P
复制代码

1 `4 ?7 |7 `" B0 v! i3 S返回3条记录并打印信息
! N8 E0 ~+ K; ~$ c. x( S' T
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); * O' m0 J! b  r+ |$ I2 W
复制代码

3 f# R9 O8 O+ F. I- R3 E. G结果
/ K% M5 V7 l  \0 h/ ?9 Y! g7 G
  1. my age is 18
    & N% h  h  ]; e
  2. my age is 19
    1 L7 a3 r' ~% o2 ~
  3. my age is 20
复制代码
+ L, o' y" P% n% h. u+ V

9 m4 _  y1 I( `9 q限制返回记录的开始点skip()
! m1 _) u4 f6 B9 i; P; n2 ]8 D4 j从第3条记录开始,返回5条记录(limit 3, 5)
" n( h  M9 r# v) @5 _" S. ^4 t( `( C/ W" I
  1. db.users.find().skip(3).limit(5);
    ! ^5 Z2 y# @$ s; [4 n) H- m& u
复制代码

% o* k0 t7 O. \, p5 l4 l查询记录条数count()
. x8 ?8 N" v* a- R' ]0 Mdb.users.find().count();
: y; K$ v5 x9 [0 {. V; ?" G( [db.users.find({age:18}).count();
' y* C% E: `! _2 }9 M以下返回的不是5,而是user表中所有的记录数量 $ Z$ e; F1 S# I* [: G
db.users.find().skip(10).limit(5).count(); 4 O/ g0 O. V, T' @3 w
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) ( m% A1 B6 [* r# _/ _" x" k
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

2 }) l/ s7 |. F2 A: c( ]* Z& I0 f. W& \( }) e
分组group()
( D) X0 ]$ V$ l6 x  m7 D# {6 e0 D假设test表只有以下一条数据
* p- s( R& R4 z% C  E* F  I* g. l' W
  1. { domain: "www.mongodb.org" 2 v9 Q8 I) C6 u; K# R& `0 ]5 C/ ^
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
    ' H* {8 O0 N& n2 D% `
  3. , response_time: 0.05 7 M  g+ @, d8 A9 t: [+ g  f8 t
  4. , http_action: "GET /display/DOCS/Aggregation" - M$ M4 S4 s% k8 W' Z' f
  5. }
复制代码

; \8 r- g7 T' S1 }3 p2 i使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count;
0 `% m3 s( R. ~3 V+ d
  1. db.test.group(
    8 O( O! H0 P* E* i% }8 r
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    9 J" r' u) V- w4 w# d# w
  3. , key: {http_action: true} & M& h9 `/ z! Q' A" F' n
  4. , initial: {count: 0, total_time:0}
    * Y+ d$ F% Q* t
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time } * J- K: ]1 z2 b/ W( z
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count } + J5 d# y) Q+ B/ g3 c
  7. } );
    : J/ t" I6 t+ {8 a

  8. ) Z! r6 U' _0 f1 ?, o/ A8 [4 J) N
  9. [ ) K3 H/ H* s" c( N6 n# }2 ^
  10. { + P( e" H% Z" N5 C3 h
  11. "http_action" : "GET /display/DOCS/Aggregation",
    # `+ M5 k$ q  Z# ^4 k- s; `
  12. "count" : 1, 9 D# Z: h( `5 i  ^
  13. "total_time" : 0.05, 0 Z8 M# W5 O6 t* V
  14. "avg_time" : 0.05 / }: B# @; Y) `
  15. } 3 k+ I0 J! I! O
  16. ]
复制代码
8 M! [" }/ _7 ~
9 T) v* Y$ S  E9 N0 S* }, M7 o* F
* ^9 x- |# L. _4 U4 G
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。
见:http://static.springsource.org/spring-data/data-mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoTemplate.html
不说废话了,我们直接来MongoDB吧。
  • Max 和Min7 A) h2 N+ @1 j
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
1 q! Q- v4 f  q' H( K3 m! h
; r! i$ R  \9 B
" b% T) b" o  ?8 ?$ J) v- M, I4 y
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
% w' b: |  \: H, K$ U
# t: Q9 k: O- u
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

  Q4 _+ G( r7 W8 |9 B1 z/ {3 A2 E- ?
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码

+ ?! T* u0 [/ B, x6 H1 E( n' F
& T, X; R4 t2 M
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
' H5 ^* y1 R+ u1 A
- |- @  E. R1 i) C' [
输出如:
  1.         
    ! g8 N9 i- x3 G9 S; V/ l
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
% l1 e" g$ V; A7 {4 s- _1 X

3 Y' _7 \* D( J
) P; G5 _& y0 j
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    7 k! c3 v9 G2 h% k+ q
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"0 f8 X( G. ~8 E, U+ V
  3.        xmlns:context="http://www.springframework.org/schema/context"
    - y3 @# _% T5 E! x6 d
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"- g' d7 h, h% P; b, i% X, k
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans4 _7 x7 ]9 E0 ~/ _
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd6 x7 ^4 n* d/ J& F
  7.           http://www.springframework.org/schema/context& B& v9 s& s" A5 J5 Q+ _
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd/ l0 G# G$ s& N( D1 |) V& _7 V
  9.           http://www.springframework.org/schema/data/mongo
    ' x# a, v% f  }7 C  p$ A  O4 h
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    % t$ v! e% x0 r( Z1 u
  11. # U- R  c) }* e7 @8 I
  12.     <context:property-placeholder location="classpath:mongo.properties" />/ W5 E9 s+ j- X  Z
  13. ; x+ M" ]# k9 e6 V. F
  14.     <!-- Default bean name is 'mongo' -->) H0 `& Y7 g0 e& e( o5 ]
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />
    , @" p: X% L1 _5 G$ H. N

  16. 1 [$ y% a: m7 }& l6 G# L' P$ g
  17.     <mongo:db-factory id="mongoDbFactory"8 o4 d3 q1 P/ o2 [
  18.                   mongo-ref="mongo"
    4 p: w: B6 m) A! v. p& ^* n
  19.                   dbname="mongotest" />( p6 O. U  S' ^; b+ _( y5 b
  20. 8 {& E, k6 k8 F% R
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    % g- ?/ e7 {: p3 k
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    " V6 s1 i4 j% L) r* L, S! T8 g4 Y
  23.     </bean>9 i( ^3 ]) v) Z+ o' n  P
  24. </beans>
复制代码

8 H: G4 H# C- P* [

2 y5 S3 T0 Z$ k& t3 S: v$ R* s
maxmin的测试
  1. @Test) x9 o& F/ m; I9 F1 u) M$ w
  2.     public void testMaxAndMinAge() throws Exception {
    : _9 ~! S5 {2 P  E& c, V: f
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    . J8 w2 H4 |/ n3 f# c
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    - g  t6 d, e4 Z7 R
  5.         log.info(result);* [2 {5 X0 S2 K! B
  6. 3 q6 x1 d- M8 ^. K! J
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    8 |) ]( A" S" v. _
  8.         result = mongoTemplate.findOne(q, Person.class);+ ?# n& B  j2 d- u) B2 V
  9.         log.info(result);
    4 P: [& n2 l6 n1 x. q+ v
  10.     }
复制代码

% \0 P" J/ \9 Q. h+ s7 \
% J2 N5 Y  o5 Q* ~
distinct的测试:
  1. @Test9 D. {- s5 d! r# P
  2.     public void testDistinct() throws Exception {6 f7 M; n: N3 N$ q; B" A' Z
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");
    ( m: P- T$ \* [% l/ v  v
  4.         for (Object o : result) {
    # l  L; V: i, ^' r. P' ^, I  V0 a
  5.             log.info(o);/ c7 {, T- r0 V
  6.         }# w3 L& y8 X& ^. w( w
  7. % ^# o* w. q* e, \: b3 o/ n1 ~+ S5 P
  8.         log.info("==================================================================");2 x9 \( z4 C( U% H9 ~8 x5 t
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));8 Z$ L9 Z& ]; b! ]) {& Z% w
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());; L; g( J; B( l
  11.         for (Object o : result) {
    9 g! s' J0 j# X6 q9 a
  12.             log.info(o);
    ' T6 q# v) ^" d  }
  13.         }
    9 c3 R, p# t( D6 V1 w

  14. / z) ^4 G' e# M+ Q: k" T8 `/ V
  15.         log.info("==================================================================");* \" x4 c" H  |6 X/ g5 V3 V% c, G
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    ; I0 }2 \5 m" m) H# t
  17.         for (Object o : result) {
    ' q! i1 S* P; H% h+ w/ m
  18.             log.info(o);
    5 U8 J& T7 ^( F; T
  19.         }9 @' |& I/ E7 e# g3 Q# j
  20.     }
复制代码
4 t( }3 y$ \1 A. h
8 |9 h6 T) A1 Y& _0 y& u; l
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 2345676 t" X' [7 x/ W. _1 M$ H
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 3456783 F& w3 x7 g! ^0 C, F; R( s
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567897 e+ e8 g& f9 u& T: n  E
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 9876540 t: Z" w+ B* g+ T" ^
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni- ^( c5 O( q8 d& _) e' p
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    + h( x! o8 @! M  }
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456; T. ~$ u/ A& O: v5 q7 L+ v4 S
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================2 R' M( c4 q( {5 }
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    ; d' u+ r+ s' t" l! Y& N5 m
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    ; l& I& D: U$ D) v" v" {& [
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567899 J1 E2 A! W7 _
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
      K4 a3 Z: }: s% W6 ~
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    6 Y0 w. B$ Q" S5 l7 R+ y
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa8 {, U3 J7 S, P* ]! \% t' B
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb1 p& H. l3 A$ P$ y3 ^
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc) O* J0 S* H- f3 _2 o* u2 K
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www
    2 |& @. U- Y  E  C- y  [
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx% c3 e& ^8 b' z7 P7 @+ ?- x8 n# ]( n
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy, m" k! Q) \% }, I6 I' G8 d/ T
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz) q+ C4 T# _9 H) I, N" n+ q
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr7 M  I6 j: _% _3 K1 \/ P8 }2 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
复制代码

7 |0 f% M& g3 `
* \( c6 E/ c5 Z! z4 h# }: V
这里我要特别说明一下, 当使用了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等信息。

2 Y; G0 y7 t' K" O2 {
+ _1 W2 X+ {% i
% J9 ?, F9 M. l/ j) _




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