Map-Reduce
Map-Reduce 是 mongodb 處理批量數據的大殺器,凡是數據量大並且定時處理能滿足需求的,都可以試着扔給 mongodb,讓它去 Map-Reduce。
以下截取自文檔的圖,可以清楚的說明 Map-Reduce 的執行過程。先看圖:
回答問題,Map-Reduce 的執行過程是先 map
然后 reduce
么?
是?恭喜入坑!而且是自己挖坑自己填。仔細再看一遍上文的圖,看到那個灰色的箭頭了?不是每次 map
都有 reduce
的!
如果 map
的結果不是數組,mongodb 就不會執行 reduce
。很合理的處理邏輯。
然后,只有入過坑才能意識到自己挖的坑:對於 map
到的數據,如果在 reduce
時希望做統一的處理,一定會發現數據結果是不完整的。
mgo 時間
mgo 是 golang 的 mongodb driver。
首先,構建測試程序。
package main
import (
"log"
"time"
"gopkg.in/mgo.v2"
. "gopkg.in/mgo.v2/bson"
)
type TestTime struct {
Id ObjectId "_id"
CreationTime time.Time
}
func main() {
session, err := mgo.Dial("127.0.0.1")
if err != nil {
log.Fatalln("Fatal error:", err.Error())
}
defer session.LogoutAll()
defer session.Close()
tc := session.DB("test").C("testtime")
t := time.Now()
id := NewObjectId()
test := TestTime{
Id: id,
CreationTime: t,
}
tc.Insert(test)
var testTime TestTime
tc.FindId(id).One(&testTime)
log.Println(t)
log.Println(t == testTime.CreationTime)
}
UTC
執行測試程序,查看 mongodb 數據
/* 0 */
{
"_id" : ObjectId("548d0b3194e33700f5ffaba9"),
"creationtime" : ISODate("2014-12-14T03:59:45.123Z")
}
時間已經是 UTC 了,沒有必要 time.Now().UTC()
,當然,執行下 .UTC()
代碼看起來更明確,也耗費不了多少 CPU,因為,.UTC()
僅僅是賦值時間的 location,其源碼如下:
func (t Time) UTC() Time{
t.loc = UTC
return t
}
精度
mgo 直接以 time.Time
類型插入 mongodb 的時間精度與 time.Now()
的時間精度是不同的:
- mgo 精度為
ms
time.Now()
精度為ns
,2014-12-14 11:59:45.123670247 +0800 CST
所以,上文 log.Println(t == testTime.CreationTime)
打印結果是 false
_id 索引
_id
是 mongodb 每個文檔必備字段,而且是默認索引,就是說不管你用不用,它都會建立索引並占用存儲空間。
在設計存儲結構時,只要能保證唯一性,即可將其作為 _id
,例如:
{
"_id" : {
"nickname" : "busyStone",
"index" : 1
},
"creationtime" : ISODate("2014-11-09T02:00:44.496Z")
}
mongodb 是支持組合索引的,那么,_id.nickname
是不是也可以作為索引用呢?
在選中的 collection 上執行 .find({"id.nickname":"busyStone"}).explain()
,nscanned
字段並不是預想中的 1,因為,建立的索引是這樣的:
{
"_id" : 1
}
所以,老老實實自己個建索引吧。