cncml手绘网

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

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:
9 g, Y2 N2 y3 O  `) b2 s5 ?# j$ J! [
1 ) . 大于,小于,大于或等于,小于或等于
- u! f7 s: d; {: y3 E6 f$ B! M9 j# w: }7 _# w
$gt:大于" I/ i  t$ c& I: W$ K/ y& C8 \! Q* R5 F
$lt:小于
) h3 O. r! C' s% ^/ l$gte:大于或等于" K& w0 N3 n& r; A* ~
$lte:小于或等于
) U4 M& Q2 F! i  u4 a7 R5 y7 M3 m
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value% I/ l- n+ }6 Y9 ~$ I5 \- d' C
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value$ Q* z$ J- d' m, I/ @
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    3 V! B4 V; l' b- V8 u
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

9 b: K! \7 J1 t! d; c
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    ' @$ Y% b- e$ r9 {) e
  2. db.things.find({j : {$gte: 4}});
复制代码

& y/ q4 z0 K8 I! E/ g- E
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码
( O( X& R4 P- F; e) T
/ X# \* ?$ A4 j" {; O* I
7 u6 b6 |2 P2 g! e3 x$ V& A
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码

5 |( G: H) P/ i& l$ A; |$ M& k2 n5 i
3) in 和 not in ($in $nin)
: [: X% h& \0 D' a6 k; [
% n9 i$ D2 a( h0 W语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码

9 ]8 Z( B, w9 h! `
例子:
  1. db.things.find({j:{$in: [2,4,6]}});+ k4 d4 B- |3 z; P/ I
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码

% K# s1 ?/ \, W
( k- e4 z0 G2 R& G! G/ t
4) 取模运算$mod
: W* b: Q' y5 A- h% V3 i, @- i$ c3 i( \  n
如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
; s/ W2 B" K1 X- l0 N2 k! i
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码
; F  c) n. d5 }# O5 A8 I

) R9 M" ~) p, P* Y5)  $all# k# }# _1 z- C: _$ }
4 w' m' W; L& M0 ~
$all和$in类似,但是他需要匹配条件内所有的值:. K. ~- ]8 U- [) d+ _6 r& [8 f

1 G4 C) Q" u9 S8 Y如有一个对象:8 c* Z- t& V8 H2 d+ \. P
  1. { a: [ 1, 2, 3 ] }
复制代码

$ L% \0 N  `/ Z: P3 n/ X2 r3 m' k
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码

: q" q1 ^5 ]1 W+ e' f
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码
% i. r* |- p. H- r
4 I1 X& l  W- ~$ `' D, |# r
6)  $size
" }% X% ~2 z3 X$ x8 q& \# q0 f/ C$ |9 o0 w  J
$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:  P1 H) o% ^0 j
4 \$ A% Q6 _* ^  V
下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码

. g' p" Q" L0 r. n
官网上说不能用来匹配一个范围内的元素,如果想找$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.
' `) s1 j# ?. X3 T" F% }
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回6 f8 N0 u2 |" s: ]/ J5 a
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
) B+ G/ }6 c# a) I$ h# n
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string; x2 P" |: M: F) r# Y
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码

5 }- q1 `4 V6 I4 o- ^
9)正则表达式$ F0 v. W6 V7 ]  l! Y! V1 z& j8 q
+ s0 S( U. b5 s' c  I
mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

6 g) Z/ r/ H8 c4 x% }! p6 `
10)  查询数据内的值
# a! u6 W9 y9 n& Z5 L6 t& W  M6 n
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
% \0 W) t6 |9 J' D. j* V
11) $elemMatch
$ ~8 U" }4 S0 _3 _/ ]* {! J3 r" X* a+ M6 i
如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) 6 u/ s3 @' _% q7 ~6 n" D
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    : m1 O: b4 U8 ~
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]& S- S5 J& X) e4 D; k% e% k7 m& ~
  4. }
复制代码
3 x' F6 L- X3 Q6 J
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )
/ e: \  z$ W% W% H# c( V! j
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 } & ^; ]9 h8 U* z1 v7 J
& V$ N. t/ A- ~$ ~' f' n$ `" L
12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码
4 N, m/ T# w. o2 ^& k" A: }
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码

8 O; W, G& C& X
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码
2 c0 D  c/ Y0 z# o! e. D
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

) k* m4 w$ c" H7 v% t5 Y
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码

# k( ?1 p  i: U3 r- z) q8 Y/ N
是不能匹配的,因为mongodb对于子对象,他是精确匹配。
! ]) s' D% h& P' w" g! H
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );
    - J8 a% {/ W# _5 i
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
! ]+ L: ?4 i% r# y2 Y! M
mongodb还有很多函数可以用,如排序,统计等,请参考原文。! D) C/ R, V2 L- C

1 O# ~. }+ h6 V0 X; gmongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:
; l# i; i! C  }7 e
+ G2 b; `1 g+ @http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions
. O% k6 P( V( Q" g1 r6 c6 S) W* r" A# g5 v( N) J: L7 w3 h
版本二:
: s2 F! V% _8 H( f- s* }2 {, x
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin

9 B/ T1 p) Z. w2 V9 D
  1. use admin
复制代码
2 b3 v& J- @3 w$ ]
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码

/ ~- Z) i0 K5 k% I2 C9 v5 ^
         3. #查看用户列表
  1.           db.system.users.find()
复制代码

& X# ]! ^1 @8 B5 X0 S, A
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码

( i5 F& a  ^8 h. M. `( @  P5 Q
         5. #删除用户
  1.           db.removeUser('name')
复制代码

! W; M% B- s. `: |
         6. #查看所有用户
  1.           show users
复制代码
# K& O' v3 V& a  l: i
         7. #查看所有数据库
  1.           show dbs
复制代码

- Y' Q) r. b) i, G0 M- x
         8. #查看所有的collection
  1.           show collections
复制代码
, D0 ?5 N  S' m* s2 l+ P
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码

4 |, t( c' M2 l* O1 X8 g* I
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码
/ w1 e5 t* {: e) Y" z% e
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

' E) G) o5 |# `& q: U" h" n
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

* L' @; G% N, J* x" V. l
        13. #查看profiling
  1.           show profile
复制代码
8 W; [+ Y$ N8 L2 i9 N) q: ^% Y, f$ K4 [
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码
% N3 ^0 I! @9 v& l9 `4 C( V
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
% V; L; u8 \! @
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

' U* f! E0 V8 D3 e, G
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码

2 ~/ i. k8 D1 b2 ?
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

, T  w! ~; n3 M
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
7 k8 _% B) h" {/ T
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码

; b, Y0 t7 F3 a' Z
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码
# U6 d# w. ^! r, g" F) Z
   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()
4 }' }2 |+ z' k
6.  高级查询
条件操作符 8 R$ K" W5 j' ]/ i7 k' f
  1. $gt : >
    7 E. P! f1 u% p& q! ]- A7 h. P
  2. $lt : < + K% u6 W2 R) a& k
  3. $gte: >= 1 f4 M9 k: m; N3 I" V
  4. $lte: <= ) |( @" E+ W1 e! s  b
  5. $ne : !=、<>
    % h  b5 l2 v/ u/ F
  6. $in : in
    , K! y; B7 `  U6 R8 G! C  L4 J
  7. $nin: not in , X- k3 N6 U1 _8 p
  8. $all: all
    . z9 U; \2 q1 S9 x' `# p3 n
  9. $not: 反匹配(1.3.3及以上版本)
复制代码

4 _. J+ P- m6 I1 g
* U' p4 p# Z$ N+ x& Q查询 name <> "bruce" and age >= 18 的数据 / a+ A; ^, ^: J, b7 {$ z2 y
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
7 e+ R7 Q( k# V- a2 C8 T
! t$ q! q0 `9 i# {) V' M
查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据 ! D5 p# V5 V+ U+ k: j4 J  ?
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码

! W6 P4 l' l6 H1 i; o$ M- g
+ `* ~, ]! ^; e0 F7 T( [4 Y) `+ y查询 age in (20,22,24,26) 的数据 ! W1 `& S7 B! M- O3 G
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
/ i9 P1 H# U! X3 ^1 [, {

9 _& u+ ^) Q! U) P2 M查询 age取模10等于0 的数据 7 O% g+ r; n: _( ]- `/ a
  1. db.users.find('this.age % 10 == 0');
复制代码

: l  X1 Y; ]7 S5 G或者
6 S4 K: P& D: @& D/ S; W
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码
0 Q$ u; e9 q9 |; }- L$ C. x

3 {9 J' Q" |- D& u& Y7 \匹配所有
5 r; A2 r6 f$ v
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码
* G, q$ s8 S+ ^/ r$ q
可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] } ! B% Y8 o" z( i* w6 L
可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] } 6 m6 W- h- M4 _' }/ y5 Q2 U
; L4 c3 y& R5 z
查询不匹配name=B*带头的记录 6 m, L! E$ M- z7 G
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

. T1 b' `0 |" G9 K查询 age取模10不等于0 的数据
! ]1 H. c* {! N& P" g; l6 I
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
' x( x) E0 [. _- ~! F$ r

) K) j0 b! U( q- u3 y) v#返回部分字段 . @3 d$ A9 t" B' C3 V
选择返回age和_id字段(_id字段总是会被返回)
" I! u  S# s! f2 P9 [; F
  1. db.users.find({}, {age:1}); ; V: `* k9 n: B) M& s, d$ Y5 `: Q
  2. db.users.find({}, {age:3}); 1 ~/ }, `5 V  Y4 B) Z* Z8 H9 S
  3. db.users.find({}, {age:true});
    # A% p, g! r4 m! C
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码

7 s- s) ]" i- Q5 c1 b0为false, 非0为true
2 K( ~! x+ E" c& F  V$ s$ {( I/ |, M$ {
选择返回age、address和_id字段 ) w( E1 \$ y) O6 O$ |
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码

( U, E& K% p: O! s  `3 v8 [) n8 X; V' j# f
排除返回age、address和_id字段 % K6 T  o) z9 k' t  M9 ^
  1. db.users.find({}, {age:0, address:false});
    ' \! y7 X. Z8 O+ X0 p& R
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

) T, P. f; x$ @0 [. h
7 w( o- t- X7 V/ t数组元素个数判断 # b- j4 O8 q" ~0 j
对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录 8 H7 C/ S8 L5 \( h/ V
匹配db.users.find({favorite_number: {$size: 3}}); % z2 l1 t  {) e: x+ N% _: x
不匹配db.users.find({favorite_number: {$size: 2}}); 5 a, r/ E0 h/ F# e# P  x
  G! l  P* v; h7 n
$exists判断字段是否存在
7 o# f6 _5 c, I# R8 ~% }( J: x% ~查询所有存在name字段的记录
4 {3 K- I( r3 m- v1 K1 J4 u
  1. db.users.find({name: {$exists: true}});
复制代码

1 X% W7 {: z5 K查询所有不存在phone字段的记录 0 f# c0 b3 Q+ T
  1. db.users.find({phone: {$exists: false}});
复制代码

: e6 q4 {/ k4 u' m+ `
6 Z4 r  b3 N! A: t  ]: c5 V" g$type判断字段类型
- a; @( n2 j2 W4 R5 s& t查询所有name字段是字符类型的 ' T$ c. t! @+ c& y; ^9 D6 \
  1. db.users.find({name: {$type: 2}}); 1 l: Q3 H  {" P3 p, ^- n7 ?
复制代码
: w) S# c5 |& ^- w& [! w. J
查询所有age字段是整型的
$ E/ V) c/ Z! b- C
  1. db.users.find({age: {$type: 16}});
    6 V( i, J6 k7 u6 M
复制代码

( w+ H6 _- g. n5 E8 S对于字符字段,可以使用正则表达式 : {, f0 w3 w- r$ @1 i3 P- _" f/ v3 I
查询以字母b或者B带头的所有记录 7 V" R$ Y4 i6 u. D
  1. db.users.find({name: /^b.*/i}); / L' c% J* X% o! D0 u# O" Z
复制代码

+ j# Z( ]/ }" D$ ~2 G$elemMatch(1.3.1及以上版本) , V4 i7 E6 U: K) ^9 g6 J! E: n$ O7 o
为数组的字段中匹配其中某个元素 ; g1 Y/ |0 E) z1 W
; \) n. ?! F9 I5 q4 z, N9 J
Javascript查询和$where查询
) V6 Q5 c4 K$ j& f查询 age > 18 的记录,以下查询都一样   J0 x- k5 p/ s
  1. db.users.find({age: {$gt: 18}}); * _! I4 D: b8 b* p4 S7 R! @
  2. db.users.find({$where: "this.age > 18"});
    , h0 q3 A- J* Z; A
  3. db.users.find("this.age > 18");
    $ I2 R7 j  C7 N. p5 ]3 J
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

2 @8 Y7 w+ Q4 ^. \4 r6 q8 e1 ~5 M  ?7 f% Z9 |* S
排序sort() 2 z# S4 [# @: ~% R0 Q/ C  n0 c0 v
以年龄升序asc ; f0 G$ _7 C2 j) \
  1. db.users.find().sort({age: 1});
    , p8 y  M# q+ _
复制代码

/ l' g) @; M6 w. t5 w以年龄降序desc
* Q7 ~  p1 v0 D% A4 T% N/ a% M( I
  1. db.users.find().sort({age: -1});
    # A; F  S8 w/ b( _) R( t( L8 Q9 o6 s
复制代码

# t  x& C: u0 O限制返回记录数量limit() , C  E$ C; L' [, Q0 S( K
返回5条记录
) M1 H+ u+ _# G# ^; G8 s) ~, X7 i: t4 Q
  1. db.users.find().limit(5);
    , b' j2 y( d# G6 Q8 _0 G: {# [
复制代码

1 |2 d/ T% S" y: u7 {) y+ s返回3条记录并打印信息 ( I' Z" o4 J  Q5 B% P" m. b
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)});
    5 R& k3 j7 f& y4 a
复制代码

- K' E% P' R: i结果 , Z* r3 |4 A2 K- |5 Y! i
  1. my age is 18
    1 i. m' K$ q; V0 J' y  h9 K; o
  2. my age is 19
    7 e2 a5 u3 j- L2 i* q( P
  3. my age is 20
复制代码
8 H- k$ {, M5 L- @; _9 g8 W: l+ f

) o3 U% c" t3 D4 W限制返回记录的开始点skip()
9 W3 E- g, P0 R/ R, V从第3条记录开始,返回5条记录(limit 3, 5) * A+ K8 Y! ^' Q' p0 @% J
  1. db.users.find().skip(3).limit(5);
    " W) b( m/ I% z( h
复制代码

! P4 ]$ m  @9 J1 X: z8 n1 b查询记录条数count()
6 N1 A5 \: J0 q( Cdb.users.find().count(); # f7 p# l, a9 u
db.users.find({age:18}).count(); ; M; w3 V$ z1 s7 U/ P, J$ Z" n' e
以下返回的不是5,而是user表中所有的记录数量
. v- p0 l$ D/ j' i& idb.users.find().skip(10).limit(5).count(); " o6 n7 @- e$ ^8 n
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) ) L) n3 j% m2 [
  1. db.users.find().skip(10).limit(5).count(true);
复制代码

5 Y6 x4 d% W$ Y8 ?6 P) c
+ |5 y, S% E/ T6 ~9 B4 V) W分组group() 8 t2 _: ?. j. O: N2 r
假设test表只有以下一条数据 & ?* z. _2 {" h  X$ v
  1. { domain: "www.mongodb.org" . ^; y0 F5 o0 {- @+ e
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"} . u2 L! {6 y: D' s; `
  3. , response_time: 0.05 - ?: N$ `) i# W9 `  @$ W8 A
  4. , http_action: "GET /display/DOCS/Aggregation"
    : F9 Q% q+ z" M/ C
  5. }
复制代码
7 Y  Q) w2 w4 n9 d; o# H, D* I
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; 0 k2 f, f& [5 l1 F
  1. db.test.group(
    1 `$ t  {/ [3 k/ n( y* g' R
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}   b& D9 p& Y& o
  3. , key: {http_action: true}
    * \! I9 a' [7 s+ V# F
  4. , initial: {count: 0, total_time:0}
    % _3 {6 }: `6 e9 Q
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    ' G) e2 ]8 t3 V9 `" ?( r
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    ! g& r: {5 ~! m
  7. } ); " B4 E; V# k1 F& N' _; K# h
  8. % r5 F# L. P, F% m" ^. {8 I& p6 |/ `9 g
  9. [ ( D3 e6 [! J$ Q$ T
  10. {
    1 }# M5 u) W4 q. z$ @2 u) j
  11. "http_action" : "GET /display/DOCS/Aggregation", . M% F( {6 W3 D
  12. "count" : 1, : }0 ]* v) b( [, P
  13. "total_time" : 0.05, 6 n; V( _! U8 }
  14. "avg_time" : 0.05 # \  ]6 r* e6 ]" Q
  15. } ) Z4 p7 Z; c& c7 i( L" l: M
  16. ]
复制代码

. P2 a$ Q, C5 I4 o
3 h( k8 z7 s3 Z% _: S" y, ~5 N5 s( O% `$ o8 f) {; z
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 和Min. y* _3 `7 y* _3 |* E8 B4 ~
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码

8 p$ R3 h$ l1 N. n; W. W- T' m$ B( U7 v1 n' B
& L9 S1 a& t6 N# t- U* c, e) I8 ?. D
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
# i2 _3 l) e+ n* t5 O; u

1 G; o4 S$ B. J+ s6 p8 D
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码

* y7 O& ]2 K9 ]' l8 c9 i2 t7 G; ]
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
6 G. c8 d7 h; I+ [. A" k1 @* V

2 P" p6 T9 g0 a, G( i
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
0 _. {" o( U" `# O) ~3 j/ U" @

. o$ m" T. P2 ~
输出如:
  1.         - A1 ^/ f/ V. d3 v8 l, i7 g2 a8 u  c
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
# M$ x; ?6 \/ N

8 d8 y& f/ {' n7 D+ _' P
( k7 _6 Q  w3 }: s' g7 O
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    ! x/ ]; v+ q7 l
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"7 [9 c2 v. y! Q/ V! R7 l0 l
  3.        xmlns:context="http://www.springframework.org/schema/context"
    ) \3 Y. C% f7 l( c  o+ P# o
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"; r, v1 w: g# L0 |
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans
    2 N* M" g# y2 Y4 k$ a: D3 W$ V1 G
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    " {4 ~1 B# f0 a+ U) J
  7.           http://www.springframework.org/schema/context$ @8 v& R2 c% W0 p1 O
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd9 W6 V( N4 u% I3 g
  9.           http://www.springframework.org/schema/data/mongo  |) j/ A% e4 |- V9 W, j% l
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">5 M/ u* p! t) d6 O# [% J

  11. ' T5 n$ k, |+ k1 E( G) _4 L
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    : P. g) N4 J$ \* q

  13. ! f& y- W8 e8 m9 S5 W9 V0 R# o( M7 T
  14.     <!-- Default bean name is 'mongo' -->
    0 Q+ _/ M5 [8 m3 J& F3 A
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />5 }8 n* j# |' w7 N& I

  16. 3 J5 k& p4 J& @) I
  17.     <mongo:db-factory id="mongoDbFactory"" F' O. p4 ^0 d- G
  18.                   mongo-ref="mongo"
    3 Q3 q4 z6 z/ m+ f" V5 t; o
  19.                   dbname="mongotest" />' E$ e' ]6 m, c

  20. 9 M! e& n2 x0 j+ w6 [
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    % F. R, z# x( G; d' G) z& n
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    / D5 ^# U5 r/ E5 o* L% J! k: j
  23.     </bean>
    $ Z0 X7 {5 L2 m6 H9 ~: h" h6 Q
  24. </beans>
复制代码

& g! F; {' C( S  O6 D, z+ e

6 i% V  t3 A, T
maxmin的测试
  1. @Test
    / O( }/ W: }0 `; ?5 }
  2.     public void testMaxAndMinAge() throws Exception {. l6 ^+ K7 d: V  P8 e$ [) N3 U* D$ P
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);$ \  {1 E5 B+ c' J, {
  4.         Person result = mongoTemplate.findOne(q, Person.class);* ^4 Y) H9 C8 [' s9 q8 q* ?8 [
  5.         log.info(result);
    : X: n' e1 {+ e* s2 R* Z
  6. ( S( z( o; B  R8 n
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);  B/ G/ Z' b5 \. q# @
  8.         result = mongoTemplate.findOne(q, Person.class);
    4 |3 ]. M4 M. B
  9.         log.info(result);- j$ M. d1 }" H6 }9 I: t+ C: }  y
  10.     }
复制代码

$ S) h" `  [( ]* Y3 E5 H6 B# ]8 C/ Q$ _9 R
distinct的测试:
  1. @Test
    8 `% \( e2 z% b9 m8 V
  2.     public void testDistinct() throws Exception {
    # `' ~7 C8 Z" G% G; v7 T# i" J
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");3 l# N) }0 [* y
  4.         for (Object o : result) {
    # T) }/ T( A  ]# Q0 ?+ e
  5.             log.info(o);
    7 [9 T: @% Q! \7 _0 D  ~
  6.         }, q! j( l" s- ?' P2 K' f" ]
  7. 3 x" @  x6 `& t$ C
  8.         log.info("==================================================================");$ }' M+ T7 Z) Y) V8 s' F
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    * c* d# f5 {6 [% ^2 n4 T
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());
    ; s8 X7 b# Z) j  o
  11.         for (Object o : result) {" V3 {" ]) A$ [( \2 l1 N
  12.             log.info(o);5 L0 s: R& q' y* M- }. c1 F! o
  13.         }  ^; I2 B! ?  Y
  14. 1 C8 `+ \5 K: k, X, `3 f
  15.         log.info("==================================================================");: T: z: L: H* K! A) J
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");9 u4 k/ V# a' B
  17.         for (Object o : result) {
    3 B5 B; S9 _9 y  s$ M! {
  18.             log.info(o);
    6 s) _+ Z2 i+ p1 I+ a# f3 |9 S
  19.         }
    ! Z& s' c% e7 F0 n
  20.     }
复制代码

& B$ V' y; K6 d
' ~  n! ?4 z1 K/ o* w
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    - g* u6 K7 J( n1 e* j$ W! @
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678  t; Q0 H5 Z* Z7 |( ]  l# X2 ]
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 456789
    4 S) K7 N6 U- b
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654# Y, ]* C  p0 i
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
      T% D$ u$ ~7 e6 E  i: d
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    + X& G1 J! m# \) F# Q
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    - G* K2 i8 J9 ]1 a" |0 q, s
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================9 u+ J# \* E$ `9 ~0 j9 T% Z8 q
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    " ^2 q( ?5 F( v" l3 o
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    5 V' G2 \4 e" e4 Z6 {* G
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 4567894 @2 w! {# I% u, i! [! \. p/ |
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 987654
    1 M9 N0 J5 H6 y
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    + F; ^" \6 P8 |; m5 J9 n
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa4 d% K, Y7 |7 u! h( g# i
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb; G. A7 H) B1 j9 l, S
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc4 T5 H( ]9 ~5 E. P
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www" W8 c0 |, b2 W' R- X0 |
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    1 v0 w  M; i4 V) P; _* g+ h
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy9 b* K" i/ {. u# L( A7 o4 r  G
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    6 e! C/ ]6 T0 W2 n3 g
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr
    # f7 \) p/ F" _8 R
  22. 12-22 14:13:45 [INFO] [support.GenericApplicationContext(1020)] Closing org.springframework.context.support.GenericApplicationContext@1e0a91ff: startup date [Sat Dec 22 14:13:44 CST 2012]; root of context hierarchy
复制代码

  ~" }4 c, n" r/ h$ |0 l) D' Q! b, z& 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等信息。

. m/ \/ K/ O: \! l
. n  w3 @3 _( i
! E. Z) Y. q: D9 q# ]0 i, b




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