cncml手绘网

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

作者: admin    时间: 2019-7-4 17:21
标题: MongoDB高级查询用法大全
版本一:
, e$ I  p0 }* Q5 }; C
" v# Z0 G* r$ J7 Y- i4 B1 ) . 大于,小于,大于或等于,小于或等于, D* r' m( v" a2 E6 U% @" f. q+ P) @4 O8 e
- }" i2 a3 k/ S7 u$ Y, |1 }6 {
$gt:大于
- r) ^3 ~6 K" K3 f7 T6 h$lt:小于( _( V3 I1 E! ], H3 c
$gte:大于或等于2 x4 M3 L' a  _2 l: j* s
$lte:小于或等于1 h# m7 A5 ~# \( e: Y* j. v
7 e6 W. _: K* n- G8 ]- W3 }
例子:
  1. db.collection.find({ "field" : { $gt: value } } );   // greater than  : field > value
    5 w1 Y6 ^4 j3 M! m' i7 m* F1 w) Q
  2. db.collection.find({ "field" : { $lt: value } } );   // less than  :  field < value$ V/ e1 \" G6 a9 T% l
  3. db.collection.find({ "field" : { $gte: value } } );  // greater than or equal to : field >= value
    , H' @' X6 R1 X. q& c
  4. db.collection.find({ "field" : { $lte: value } } );  // less than or equal to : field <= value
复制代码

3 D# K% @9 v: H1 x
如查询j大于3,小于4:
  1. db.things.find({j : {$lt: 3}});
    + E2 I5 i- T( g% E8 G
  2. db.things.find({j : {$gte: 4}});
复制代码

, D3 E$ H7 `/ H% a: j; g$ I
也可以合并在一条语句内:
  1. db.collection.find({ "field" : { $gt: value1, $lt: value2 } } );    // value1 < field < value
复制代码

0 h4 ~5 Z" a% D5 ^# \6 T
6 Y5 u0 J# T6 w
2 [# Q4 R# O9 Q* ?9 m2 y
2) 不等于 $ne
例子:
  1. db.things.find( { x : { $ne : 3 } } );
复制代码
1 }2 M& t3 }2 W: e
3) in 和 not in ($in $nin)
( P  ]; Y7 R+ ]0 [9 F4 v9 Y8 _1 e- e: p
语法:
  1. db.collection.find( { "field" : { $in : array } } );
复制代码
1 ^* }8 B. w2 r. W1 w
例子:
  1. db.things.find({j:{$in: [2,4,6]}});
    8 ~) \9 X0 N! Z; w3 P
  2. db.things.find({j:{$nin: [2,4,6]}});
复制代码
/ ^2 y, Y# \. y& B1 `

& `9 h5 F0 f: F6 K4) 取模运算$mod
# Y9 G& Z- s) i4 r5 O0 Y5 ?+ n
. S% E3 N. c; }( l如下面的运算:
  1. db.things.find( "this.a % 10 == 1")
复制代码
$ m/ J' J% H- M/ g, B5 a
可用$mod代替:
  1. db.things.find( { a : { $mod : [ 10 , 1 ] } } )
复制代码

& b3 J2 B2 C' s1 f  F

+ N+ t- T  D7 m% z5)  $all" S& g6 p4 u  y9 t" h
6 ~5 q+ c" s7 F( W
$all和$in类似,但是他需要匹配条件内所有的值:
& a% h1 M6 F2 }9 F
9 F( z, @/ w) ?* T! d; M如有一个对象:& y! `$ }+ {0 E. k
  1. { a: [ 1, 2, 3 ] }
复制代码
/ g0 j) z& J' r1 d  ^1 U5 j, L' i
下面这个条件是可以匹配的:
  1. db.things.find( { a: { $all: [ 2, 3 ] } } );
复制代码
1 T: z/ }( A! i: g* h. b
但是下面这个条件就不行了:
  1. db.things.find( { a: { $all: [ 2, 3, 4 ] } } );
复制代码

' m, y. c' z5 {2 a1 w
7 s8 z; l/ |, n* F) L" v4 P
6)  $size
% h+ A/ W4 T8 [, Z) Y
5 w" c7 ~! R+ t$size是匹配数组内的元素数量的,如有一个对象:{a:["foo"]},他只有一个元素:
$ D0 C7 g% ]& g# S
0 P' `0 A5 o$ r' J3 w$ m下面的语句就可以匹配:
  1. db.things.find( { a : { $size: 1 } } );
复制代码
$ x  p! u0 Y$ j3 M1 W
官网上说不能用来匹配一个范围内的元素,如果想找$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.
( e3 Z% r0 L: S7 k! ~2 o9 Q
7)$exists
$exists用来判断一个元素是否存在:
如:
  1. db.things.find( { a : { $exists : true } } ); // 如果存在元素a,就返回' y6 a" w+ R  h
  2. db.things.find( { a : { $exists : false } } ); // 如果不存在元素a,就返回
复制代码
" q4 D& X$ y! u! v: f! ]
8)  $type
$type 基于 bson type来匹配一个元素的类型,像是按照类型ID来匹配,不过我没找到bson类型和id对照表。
  1. db.things.find( { a : { $type : 2 } } ); // matches if a is a string1 l! Y0 D2 `4 v. O0 `
  2. db.things.find( { a : { $type : 16 } } ); // matches if a is an int
复制代码
7 L8 L6 j9 J8 Z; x- k+ x5 q
9)正则表达式7 d* t+ D2 c7 |7 H& |5 L; u

9 G; M/ W8 X6 \2 u0 \( o8 E9 d* y1 h& p2 [mongo支持正则表达式,如:
  1. db.customers.find( { name : /acme.*corp/i } ); // 后面的i的意思是区分大小写
复制代码

- f$ A) v' |+ T
10)  查询数据内的值) L! a) J. w2 L' V9 F
% [+ U$ V/ G8 U$ v- n- Y
下面的查询是查询colors内red的记录,如果colors元素是一个数据,数据库将遍历这个数组的元素来查询。
  1. db.things.find( { colors : "red" } );
复制代码
& ^' a1 d: A5 ^9 F! H
11) $elemMatch
: M5 E1 I: l& M
1 y2 X% ^; s& o( s如果对象有一个元素是数组,那么$elemMatch可以匹配内数组内的元素:
  1. > t.find( { x : { $elemMatch : { a : 1, b : { $gt : 1 } } } } ) ( o" J6 n  i# a* c7 U1 L
  2. { "_id" : ObjectId("4b5783300334000000000aa9"),  
    ; b/ W: j3 B% Z7 {" {( R% T
  3. "x" : [ { "a" : 1, "b" : 3 }, 7, { "b" : 99 }, { "a" : 11 } ]. k2 j, `  p; g* B/ q# Y# v
  4. }
复制代码
& c* r" d3 v# D, x
$elemMatch : { a : 1, b : { $gt : 1 } } 所有的条件都要匹配上才行。
注意,上面的语句和下面是不一样的。
> t.find( { "x.a" : 1, "x.b" : { $gt : 1 } } )/ S3 f6 V# v6 K- `
$elemMatch是匹配{ "a" : 1, "b" : 3 },而后面一句是匹配{ "b" : 99 }, { "a" : 11 }
5 q# {. ]: F. S" p% W* o
. N& s( e6 y) K5 q1 N12)  查询嵌入对象的值
  1. db.postings.find( { "author.name" : "joe" } );
复制代码

3 ?5 p$ |, D9 Z$ c; P
注意用法是author.name,用一个点就行了。更详细的可以看这个链接: dot notation
举个例子:
  1. > db.blog.save({ title : "My First Post", author: {name : "Jane", id : 1}})
复制代码
+ u- V7 A) o& f5 O' N8 L' b
如果我们要查询 authors name 是Jane的, 我们可以这样:
  1. > db.blog.findOne({"author.name" : "Jane"})
复制代码

; I; Z2 X: C/ O7 O$ ?
如果不用点,那就需要用下面这句才能匹配:
  1. db.blog.findOne({"author" : {"name" : "Jane", "id" : 1}})
复制代码

) k. v' m' J+ K( G. e
下面这句:
  1. db.blog.findOne({"author" : {"name" : "Jane"}})
复制代码
( _" M" B1 s) D: K9 V1 @0 Q! z, o
是不能匹配的,因为mongodb对于子对象,他是精确匹配。

0 r# ?' w9 @4 D- A: [5 P0 j
13) 元操作符 $not 取反
如:
  1. db.customers.find( { name : { $not : /acme.*corp/i } } );4 x  V; i1 }9 z. e) v' M
  2. db.things.find( { a : { $not : { $mod : [ 10 , 1 ] } } } );
复制代码
# [9 e8 V' s2 P* C
mongodb还有很多函数可以用,如排序,统计等,请参考原文。
! j# W  A" j" n
" F7 T' l) y0 E8 S; H; ]mongodb目前没有或(or)操作符,只能用变通的办法代替,可以参考下面的链接:/ w7 w& C" }+ X1 T! [, f9 x/ U$ I

5 X4 j7 N$ f4 U- E7 K5 x% v% b0 z2 W- @http://www.mongodb.org/display/DOCS/OR+operations+in+query+expressions" t4 R! v2 r. ^0 D  C

- ^5 _+ V7 j: |& C2 e版本二:3 O1 |2 R  z# v4 G
shell 环境下的操作:
   1.  超级用户相关:
         1. #进入数据库admin
0 `; H/ h$ r* J3 u
  1. use admin
复制代码

. L' T- I1 v8 r/ k# _
         2. #增加或修改用户密码
  1.           db.addUser('name','pwd')
复制代码
: Z8 v4 R/ n8 l2 C7 v* J
         3. #查看用户列表
  1.           db.system.users.find()
复制代码
' \4 b- @7 }7 i! L# l0 v* i
         4. #用户认证
  1.           db.auth('name','pwd')
复制代码
( V) c' L# i3 V; l' |3 v3 e3 c* b
         5. #删除用户
  1.           db.removeUser('name')
复制代码
: B3 Z0 X- i' H! y
         6. #查看所有用户
  1.           show users
复制代码

% A+ u' `% P! U- A
         7. #查看所有数据库
  1.           show dbs
复制代码

! }% }( t1 [- N+ p6 r
         8. #查看所有的collection
  1.           show collections
复制代码

( K' C$ a% l1 I" u$ A
         9. #查看各collection的状态
  1.           db.printCollectionStats()
复制代码
1 [% r7 T: N; }9 ^: M
        10. #查看主从复制状态
  1.           db.printReplicationInfo()
复制代码

! E! o. c8 Y8 l
        11. #修复数据库
  1.           db.repairDatabase()
复制代码

& V7 K6 l* S, u3 h
        12. #设置记录profiling,0=off 1=slow 2=all
  1.           db.setProfilingLevel(1)
复制代码

& e7 u- V, T) _- F/ L) c
        13. #查看profiling
  1.           show profile
复制代码
4 \( I5 m; Y" O' l1 u$ J' U
        14. #拷贝数据库
  1.           db.copyDatabase('mail_addr','mail_addr_tmp')
复制代码

, f1 \, C, x: a  N
        15. #删除collection
  1.           db.mail_addr.drop()
复制代码
9 h6 d' v* h. p) _7 I
        16. #删除当前的数据库
  1.           db.dropDatabase()
复制代码

# i9 @1 k/ t* ]( o
   2. 增删改
         1. #存储嵌套的对象
  1.              db.foo.save({'name':'ysz','address':{'city':'beijing','post':100096},'phone':[138,139]})
复制代码
- ?8 e! w/ N, P1 b
         2. #存储数组对象
  1.              db.user_addr.save({'Uid':'yushunzhi@sohu.com','Al':['test-1@sohu.com','test-2@sohu.com']})
复制代码

+ t! K3 f6 y$ |) ^
         3. #根据query条件修改,如果不存在则插入,允许修改多条记录
  1.             db.foo.update({'yy':5},{'$set':{'xx':2}},upsert=true,multi=true)
复制代码
) P9 E, |1 {6 a6 q3 E, s8 N; }% [
         4. #删除yy=5的记录
  1.             db.foo.remove({'yy':5})
复制代码
6 [' {9 l. f7 ?' B# w" D& ~
         5. #删除所有的记录
  1.             db.foo.remove()
复制代码

: l" M# m2 W; O/ j
   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()
# P, `9 [$ \: |" q- b
6.  高级查询
条件操作符
9 `* E* k9 N" K0 f! _, j5 @+ P
  1. $gt : >
    + A" Y% H9 U/ I+ P/ Y
  2. $lt : <
    $ e7 |. I5 R/ k8 {1 e
  3. $gte: >=
    6 \' `9 i8 t2 r# V
  4. $lte: <=
    : w8 A0 Q% {5 R5 l6 ?
  5. $ne : !=、<>
    3 o7 H% [* T( a1 O& P
  6. $in : in 5 X0 |8 Q# M# N5 ~- F3 z( P! ~
  7. $nin: not in + s9 O/ ^  i+ f
  8. $all: all ! e6 I) y. m  L2 [. D
  9. $not: 反匹配(1.3.3及以上版本)
复制代码
. Z% A6 |% |* Q4 h0 S! f/ `

$ t" w; O6 {! [3 v' h查询 name <> "bruce" and age >= 18 的数据 1 }: _/ s* g4 \' m, f: x& \( T
  1. db.users.find({name: {$ne: "bruce"}, age: {$gte: 18}});
复制代码
# R2 \: \8 n" w9 k" h

  U$ t$ {6 N; b$ u  p% `查询 creation_date > '2010-01-01' and creation_date <= '2010-12-31' 的数据
# a- j- P7 n  h7 M" h/ P6 V- Y
  1. db.users.find({creation_date:{$gt:new Date(2010,0,1), $lte:new Date(2010,11,31)});
复制代码
3 _/ u/ _' X! Q# t! K6 p/ L) X

  l3 l+ {* ]- M. h查询 age in (20,22,24,26) 的数据
  j8 C) Y2 m$ q
  1. db.users.find({age: {$in: [20,22,24,26]}});
复制代码
+ {1 B, g; f# m$ B* f" {
, _5 c2 \) |7 ]* j4 H/ H
查询 age取模10等于0 的数据
- ]$ v) S3 A/ I$ X3 {0 Q
  1. db.users.find('this.age % 10 == 0');
复制代码

/ q$ `+ q6 r* X5 v  T- i" b4 d或者 8 G2 o( d# D; R- K; I
  1. db.users.find({age : {$mod : [10, 0]}});
复制代码

1 z* k, x; ]2 G1 j& z& V3 G2 B" M  d% P/ o
匹配所有
" h4 y0 x2 t* f* k2 q
  1. db.users.find({favorite_number : {$all : [6, 8]}});
复制代码

$ M3 S" f# `& f5 H+ @" O9 g可以查询出{name: 'David', age: 26, favorite_number: [ 6, 8, 9 ] }
; v# q3 k* Q* T可以不查询出{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
% }  r: A9 r# u# D# L0 _0 E- B
2 f& d5 o& V# J7 Q查询不匹配name=B*带头的记录 9 }! I* B& r2 y1 d7 L7 u) e6 \
  1. db.users.find({name: {$not: /^B.*/}});
复制代码

( J. u) I5 P# W  |# J( H查询 age取模10不等于0 的数据
/ E+ Q& `/ H& y- m+ r& E2 I& o
  1. db.users.find({age : {$not: {$mod : [10, 0]}}});
复制代码
, a) K) q6 r/ d/ N8 c% `  a
0 O  X+ o2 `! K( G' X3 i& b/ n9 n
#返回部分字段 ' \: E. g+ N! B7 Z! _' K' @
选择返回age和_id字段(_id字段总是会被返回) + c. s- C" T3 e" z- ^: L6 l- e; D6 i
  1. db.users.find({}, {age:1});
      u* E& h) D" H: p0 K9 i3 \
  2. db.users.find({}, {age:3}); % G% E8 w* I' [
  3. db.users.find({}, {age:true}); 0 \, v6 t+ e7 h/ g8 v& ?
  4. db.users.find({ name : "bruce" }, {age:1});
复制代码
3 E+ s1 ~3 p  N5 W
0为false, 非0为true
8 ]2 O' |" J. V7 J& r. b* s; _. N
选择返回age、address和_id字段
* W& E4 G( h1 l0 H7 k! a
  1. db.users.find({ name : "bruce" }, {age:1, address:1});
复制代码
; a8 I. f3 F# [
+ `  U* y$ s, _: y! o9 f
排除返回age、address和_id字段
" K  J6 d1 E) E. T
  1. db.users.find({}, {age:0, address:false});
    ( h% q8 ?7 n6 E2 |* Q/ O; M
  2. db.users.find({ name : "bruce" }, {age:0, address:false});
复制代码

  D6 K0 s& o0 P' d4 @( W
: N# r* X8 Y2 M+ s5 y数组元素个数判断
& V: _0 s  M, D8 W* Q' {  c1 l0 s对于{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }记录
  u" n0 _, K! F" T2 G匹配db.users.find({favorite_number: {$size: 3}}); ' ]" T0 Q2 i3 u. B6 H0 [! [5 h2 s2 ?
不匹配db.users.find({favorite_number: {$size: 2}});
+ `2 Z. c& O5 c
# t" Y+ D" W1 q2 q. B7 ?! \9 }$exists判断字段是否存在
% w, \0 G, ^+ \" m查询所有存在name字段的记录 - y2 n) K; e" {, Z) Z2 s5 u  }
  1. db.users.find({name: {$exists: true}});
复制代码

& v( E* |/ S3 e6 i+ g* g查询所有不存在phone字段的记录 + |. A, u6 X8 ?, {& g& o: ~
  1. db.users.find({phone: {$exists: false}});
复制代码

- _. i' B4 {6 w3 ~' e
6 A  N& g2 b0 l! N: o. ^$type判断字段类型
3 h, r9 C4 ^- A5 w, N/ k9 V! c查询所有name字段是字符类型的 - F* a; z( _  |
  1. db.users.find({name: {$type: 2}}); 6 y) N0 I( J. T6 ^3 a
复制代码

  p  `7 T' J, U. I* R7 x7 s查询所有age字段是整型的 ; m$ E4 P" w0 Z: G9 a; n/ G/ B$ @
  1. db.users.find({age: {$type: 16}}); 1 |. f( e. k5 R. b* X3 {- c
复制代码
6 W# U8 C5 a- F. c
对于字符字段,可以使用正则表达式
; G. P, m/ |; v; ]0 }$ [查询以字母b或者B带头的所有记录
* N. H& F: R0 x9 g0 L
  1. db.users.find({name: /^b.*/i});
    ' U- B0 Q9 i: [( K
复制代码
! B3 [/ h$ e' b9 P* g7 e/ y
$elemMatch(1.3.1及以上版本)
( H; v3 N( P+ y% A5 k为数组的字段中匹配其中某个元素 + t5 E* t& G! f0 C  i
/ a' ]' m6 Q# U3 s+ U# t0 ?
Javascript查询和$where查询
, n4 `( }- M" O9 Y) ]; y7 }查询 age > 18 的记录,以下查询都一样 " o3 g3 d% z( |4 x3 C1 S1 y# F5 t
  1. db.users.find({age: {$gt: 18}});
    ' ^9 \- A7 k, t4 _
  2. db.users.find({$where: "this.age > 18"}); - q0 h! |- N* X2 R. ^: F' w3 e
  3. db.users.find("this.age > 18");
    1 |6 U& j  n+ a" Y9 Z
  4. f = function() {return this.age > 18} db.users.find(f);
复制代码

, i" M$ d1 A" q% ^/ Z3 J2 V
; A) f/ t7 c; b; I: \排序sort() 9 U, X% g) R8 O/ k/ @
以年龄升序asc & O8 }' F+ u! q, B. U  v3 g% l4 g9 G
  1. db.users.find().sort({age: 1}); 5 g; V& x$ v  `; c$ w
复制代码

- I0 {# Q! u! g; u7 M以年龄降序desc
. U: p, ]9 _; k# O5 ~* A. N
  1. db.users.find().sort({age: -1});
    % {4 Z7 c& i$ I6 F( V( {
复制代码
2 H! J* o4 w; h
限制返回记录数量limit()
0 ^* q6 u3 W$ M5 C/ f* a+ @, S返回5条记录 / Y; M# @7 p; N9 S% l
  1. db.users.find().limit(5); " `! s" X& t9 `) f
复制代码

4 Q' s4 M+ m! V7 v9 l返回3条记录并打印信息
' h. C; [/ {  r2 {+ F8 g
  1. db.users.find().limit(3).forEach(function(user) {print('my age is ' + user.age)}); - b; v' ]( c5 Z7 e
复制代码

# c( K7 J4 n! ~( ^结果 ' _4 {- n$ p; S2 ?
  1. my age is 18 ; l& P0 V: S6 x3 P; N
  2. my age is 19 5 ^) y! t# E7 o( }
  3. my age is 20
复制代码

, n$ p" \1 v9 i: X
  m' w) c8 G1 d8 s6 k限制返回记录的开始点skip() 4 d/ D! C& F5 l2 K& |0 R5 X- |
从第3条记录开始,返回5条记录(limit 3, 5)
2 J0 [$ F8 I% _- `: N4 H
  1. db.users.find().skip(3).limit(5); ! m2 ~8 ?; ?: Z  _# k7 H
复制代码
8 r1 E4 q7 P% v3 O7 t
查询记录条数count() 5 c) d* F6 Q+ h* r: Q6 M
db.users.find().count();
; }. u2 ?1 g5 Ddb.users.find({age:18}).count(); 9 q' }2 C) j% g* B- V
以下返回的不是5,而是user表中所有的记录数量
% x4 N- V" E6 D; Y" P" V" p/ U$ L, fdb.users.find().skip(10).limit(5).count(); . i) ^7 I1 p* l# {; d, ?' f
如果要返回限制之后的记录数量,要使用count(true)或者count(非0)
4 i- e( U6 G' d* M- |! e7 O* f: ~
  1. db.users.find().skip(10).limit(5).count(true);
复制代码
1 y0 F. B* y% M  w. Y0 T* r, M+ h' V# N
. H% Z9 c8 k$ z* D4 n
分组group() 3 f+ z4 Y% l- l! j5 K( ?) ?
假设test表只有以下一条数据 2 m) j6 S5 u1 S) c- B8 B
  1. { domain: "www.mongodb.org"
    3 ?' e$ o+ @+ [* X3 Q3 l& i$ H3 k
  2. , invoked_at: {d:"2009-11-03", t:"17:14:05"}
      y# N; \2 P2 o0 e
  3. , response_time: 0.05
    1 v" J3 B, s( d7 x* W
  4. , http_action: "GET /display/DOCS/Aggregation"
    0 b, w# h" x/ m1 X! ~
  5. }
复制代码
- r. E7 K- m" j/ g) [" v6 r0 Y9 n
使用group统计test表11月份的数据count:count(*)、total_time:sum(response_time)、avg_time:total_time/count; * x) h- n3 f+ N' ^) o% ?7 y* K% N
  1. db.test.group( / S! N/ q7 q* L9 g+ Y
  2. { cond: {"invoked_at.d": {$gt: "2009-11", $lt: "2009-12"}}
    ! D& K- L7 e3 R
  3. , key: {http_action: true}
    ( X# ], V3 I& ^$ l% _+ p
  4. , initial: {count: 0, total_time:0}
    8 u9 j! N. p* `, v+ ?% N
  5. , reduce: function(doc, out){ out.count++; out.total_time+=doc.response_time }
    6 j' T! y: p# K$ t8 W7 w
  6. , finalize: function(out){ out.avg_time = out.total_time / out.count }
    6 ?: O) O* ~& f2 p; x) ?3 `
  7. } );
    " k" f$ q: h# X' D

  8. 6 e  }7 e+ L5 V9 r0 V
  9. [ 7 {& Y' P- J! j' q
  10. { / o& ^# A( ?' d+ T) q* i3 o0 _0 H0 E0 ]
  11. "http_action" : "GET /display/DOCS/Aggregation",
    6 n7 O5 M3 I4 q) t8 B0 W- G8 W
  12. "count" : 1,
    * o) I1 C, m% x/ g
  13. "total_time" : 0.05,
    # G% u  h  S" h7 S1 w
  14. "avg_time" : 0.05 ! z1 x4 E+ e4 y2 f
  15. } % \, u% h5 E) P4 S' B. E
  16. ]
复制代码
& x) _9 l0 }1 @4 G0 H, C4 n
/ @, h+ P4 w" y4 Q+ M3 z7 |* }

3 p& d0 ~& n& ?6 c2 K6 a; y- D$ {' vMongoDB 高级聚合查询
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 和Min8 A, z0 e4 f; g  B$ n7 Y
我和同事在测试Mongo时,索引还写了不到一半,他想查询某个字段的最大值,结果找了半天文档也没找到关于max的函数。我也很纳闷这是常规函数啊怎么不提供? 后来经过翻阅资料确定Mongo确实不提供直接的max和min函数。但是可以通过间接的方式[sort 和 limit]实现这个。
要查询最大值我们只需要把结果集按照降序排列,取第一个值就是了。
如我的例子,我想取得集合中年龄最大的人。
  1. db.person.find({}).sort({"age" : -1}).limit(1)
复制代码
& u, x+ C  c+ N- m7 _
! s# X  _% s1 ~1 u+ x( s3 d
. k* \- T. \7 K# C6 O9 L( a6 ?
相反如果想要年龄最小的人,只需要把sort中改为{“age”:1}就可以了。
当然我们使用了sort,对于小数量的文档是没问题的。当对于大量数据需要给age建立索引,否则这个操作很耗时。
MongoDB的destinct命令是获取特定字段中不同值列表的最简单工具。该命令适用于普通字段,数组字段[myFriends]和数组内嵌文档[fruits].
如上面的图片,我认为fruits和myFriends字段是不同的。网上很多资料和例子都没说到这个情景,因为我们也业务是fruits这样的模型,我测试了。对于fruits.fruitId他也是可行的。
如上面的表结构,我想统计所有的喜欢的水果。
  1. db.person.distinct("fruits.fruitId") // 查找对象里引入对象的值,直接加.
复制代码
2 Y* I! f# T& y! _
2 }; g9 _" V2 d. e6 ~' S% P5 }& O
他成功执行了。输出如:
  1. [ "aaa", "bbb", "ccc", "www", "xxx", "yyy", "zzz", "rrr" ]
复制代码
2 t$ G- R  b* Y& K' R- N6 a
( C- G+ Q7 \" z2 H
我想统计集合中共有多少个人[按名字吧]
  1. db.person.distinct("manName")
复制代码
8 u7 {: ]: b9 B' B9 I6 c. s( D

( K4 s( x! F- x0 A& H% j  n4 N
我想统计指定个数的人的共同关注的朋友。
  1. db.person.distinct("myFriends", {"manName" : {"$in" : ["ZhenQin", "YangYan"]}})
复制代码
5 ?3 {% X# H5 l7 b1 @/ x) H( v

: ]  @; A% z! C  E: [
输出如:
  1.         
    2 x2 S, w1 ~! g% m. n
  2. [ "234567", "345678", "456789", "987654", "ni", "wo" ]
复制代码
! F* Y0 o% Y3 ?* ?% a  C7 d

" h. i. c: C5 ]( C3 h+ d
7 k) h0 \. h( |2 w% c3 r! d
那么我使用Java呢? 我只是在演示Mongo的命令,用Spring Data Mongo是怎么操作的?
Spring Schema:
  1. <beans xmlns="http://www.springframework.org/schema/beans"
    9 g& O9 A: U' n+ w4 U! }1 l
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    8 {, `2 ?! Q9 z6 m" `7 ]8 N
  3.        xmlns:context="http://www.springframework.org/schema/context"
    7 n. ]* ^; n1 v/ L+ |/ o( D9 _; q
  4.        xmlns:mongo="http://www.springframework.org/schema/data/mongo"# U' ]' o/ F/ k8 H( A$ V5 R5 Q
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans" E9 M. I% G( O& B% l2 l2 m
  6.           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  l  O) j* u# ^2 n, x2 J4 O
  7.           http://www.springframework.org/schema/context% h" g7 I/ P" z& \' C& e8 A
  8.           http://www.springframework.org/schema/context/spring-context-3.1.xsd6 a3 a/ H) M6 @# A; M
  9.           http://www.springframework.org/schema/data/mongo- c' ]& q3 G3 U" p% M' F5 [- f
  10.           http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd">
    / r: P- i* |3 @  l$ s

  11. , v) c5 Q( p/ i0 d, Y0 `
  12.     <context:property-placeholder location="classpath:mongo.properties" />
    6 w2 A  V1 h" O# K& m
  13. 5 q: ~  @0 P; \) E7 @
  14.     <!-- Default bean name is 'mongo' -->% L, n0 X% K2 i0 d6 n* C( f
  15.     <mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}" />8 t$ m4 \5 l( h$ c( c# }3 I1 `
  16. 4 [0 M/ l; B* F3 t% t
  17.     <mongo:db-factory id="mongoDbFactory"
    7 w; I. \* C& j/ F% H
  18.                   mongo-ref="mongo"
    , f0 D+ R8 Y/ t
  19.                   dbname="mongotest" />. S/ k; a: N7 i3 f1 p" Y  J$ @+ J! `
  20. # U2 G( q. P9 u1 e8 f
  21.     <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">2 P% [4 f/ Q( k5 n, @
  22.         <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
      A" W2 C! W6 Z  P: p/ }
  23.     </bean>* r# J) U* p: b! |' P
  24. </beans>
复制代码
; c# u; U& q+ A
: r% N, R& H8 J0 z% M" B% u
maxmin的测试
  1. @Test
    " ~: ^' Y1 ?3 ]4 U7 A
  2.     public void testMaxAndMinAge() throws Exception {' i3 b7 [6 l9 G4 h) A6 B* D2 S
  3.         Query q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.ASC, "age"))).limit(1);
    . o) b; D5 S( W  m1 v, f- x
  4.         Person result = mongoTemplate.findOne(q, Person.class);
    4 S4 C/ e- U0 Y' V9 p3 P
  5.         log.info(result);& q9 g, j: n0 C9 w. f. h* F. V

  6. 2 G- _& `8 F/ u6 B
  7.         q = new BasicQuery("{}").with(new Sort(new Sort.Order(Sort.Direction.DESC, "age"))).limit(1);
    0 W6 O, |* V( B5 i# A6 G5 Q" `
  8.         result = mongoTemplate.findOne(q, Person.class);
    9 C& o# C- b+ e) J
  9.         log.info(result);
    % [' [+ Y9 s0 ?  [( Y5 F8 i$ h
  10.     }
复制代码

$ h' |1 @9 m5 K0 ^; E6 a$ D4 V8 l9 \; z3 H
distinct的测试:
  1. @Test* G; K. g5 w/ C% Z  |) ?: @
  2.     public void testDistinct() throws Exception {4 j& n" X* j; M
  3.         List result = mongoTemplate.getCollection("person").distinct("myFriends");+ j! E1 y4 t3 K9 l* \. {; i; T
  4.         for (Object o : result) {
    8 E$ A* E. I: e3 u% C1 T0 D. Q( A
  5.             log.info(o);
    0 T  {8 `1 J, K! A' L; k
  6.         }
    ( {1 H6 y; g, M& t3 A9 o
  7. 7 @' L$ i7 }. r2 n, N
  8.         log.info("==================================================================");/ b) U8 e% I! p% q% U5 o! V) |
  9.         Query query = Query.query(Criteria.where("manId").is("123456"));
    4 y/ ^, t2 }. S
  10.         result = mongoTemplate.getCollection("person").distinct("myFriends", query.getQueryObject());0 @  h0 E- T7 M( |
  11.         for (Object o : result) {' u' Q3 |* n3 e
  12.             log.info(o);
    1 r8 A# w, g# F
  13.         }
    6 X9 u6 W& f0 o' }7 Y! {8 y

  14. 0 l0 @  i1 m$ s/ X
  15.         log.info("==================================================================");( w; a. \; G, M) c! D& V4 `' V
  16.         result = mongoTemplate.getCollection("person").distinct("fruits.fruitId");
    : D. z  C# p& g. |- _
  17.         for (Object o : result) {
    , b4 |, F% ], k
  18.             log.info(o);
    - K  E( p1 F- D# T* T
  19.         }8 |3 f' k& O% f
  20.     }
复制代码
2 U% B  a; j2 ~9 ?2 F8 |

' f) M3 ^+ @- B5 Q0 Z, Q" L- o
输出的结果为:
  1. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 234567
    : @, p& n& p) e, s. F1 v) a
  2. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 345678
    / N1 ]1 F+ p# k: S
  3. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 4567896 K" a7 m+ ], o8 J; p
  4. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 987654% o( j; E- a, _& G& y! a  {
  5. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] ni
    ; a& B' P5 x2 g4 \- M
  6. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] wo
    ( u6 C4 Y# M8 u/ ?& m
  7. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(72)] 123456
    8 J( e& T# C" r6 s- g1 b
  8. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(75)] ==================================================================* d! f% D. A7 L& d- j* M
  9. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 234567
    ( k1 m9 s8 r# y
  10. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 345678
    8 k; U0 Y- ]7 \
  11. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 456789" h( `6 f( `9 s/ ~! W2 g7 E
  12. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(79)] 9876544 t5 Z$ \! |$ s6 p" K9 j  A
  13. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(82)] ==================================================================
    6 u3 @# r' M2 H# n: A6 ^
  14. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] aaa
    ! g: [- R* M' e) J% N0 z3 }
  15. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] bbb% L) }7 W# R! c5 E0 h
  16. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] ccc
    ! a8 X. j* Q: B) o
  17. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] www) h& D# ?2 K. I7 D) y
  18. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] xxx
    - b$ U3 Z* u. c0 q, ?! x  h
  19. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] yyy$ m4 P; f( X0 F. s7 d% R  r3 z$ {: e
  20. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] zzz
    % P% w0 e' {& ^3 W
  21. 12-22 14:13:45 [INFO] [t.MongoAdvaceQueryTest(85)] rrr( k% A( E# z+ T/ E/ p( i" k, z
  22. 12-22 14:13:45 [INFO] [support.GenericApplicationContext(1020)] Closing org.springframework.context.support.GenericApplicationContext@1e0a91ff: startup date [Sat Dec 22 14:13:44 CST 2012]; root of context hierarchy
复制代码
1 c0 G5 L# h4 Q# ^" }' H
' o, U- P6 v8 `9 u( i% z! G$ I3 J7 f
这里我要特别说明一下, 当使用了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等信息。

/ r- {/ w% v) ]6 Y" K& Z8 l, x9 x" |5 \) [4 X. @0 _8 C
+ F, O& K5 g! ]" Q. R1 S





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