我正在尝试使用mgo库进行批量upsert。我正在阅读关于批量upsert的documentation,因为这是我第一次使用MongoDB,看起来我必须提供要更新的文档对。
在我的函数中,我执行查找全部查询,然后使用查询中的结果作为bulk.Upsert()
操作的对的现有部分。我不确定这是否是正确的方法,但我必须一次在〜65k文件上进行upsert。
以下是类型结构,以及从通道读取以执行上述MongoDB操作的工作池功能。
// types from my project's `lib` package.
type Auctions struct {
Auc int `json:"auc" bson:"_id"`
Item int `json:"item" bson:"item"`
Owner string `json:"owner" bson:"owner"`
OwnerRealm string `json:"ownerRealm" bson:"ownerRealm"`
Bid int `json:"bid" bson:"bid"`
Buyout int `json:"buyout" bson:"buyout"`
Quantity int `json:"quantity" bson:"quantity"`
TimeLeft string `json:"timeLeft" bson:"timeLeft"`
Rand int `json:"rand" bson:"rand"`
Seed int `json:"seed" bson:"seed"`
Context int `json:"context" bson:"context"`
BonusLists []struct {
BonusListID int `json:"bonusListId" bson:"bonusListId"`
} `json:"bonusLists,omitempty" bson:"bonusLists,omitempty"`
Modifiers []struct {
Type int `json:"type" bson:"type"`
Value int `json:"value" bson:"value"`
} `json:"modifiers,omitempty" bson:"modifiers,omitempty"`
PetSpeciesID int `json:"petSpeciesId,omitempty" bson:"petSpeciesId,omitempty"`
PetBreedID int `json:"petBreedId,omitempty" bson:"petBreedId,omitempty"`
PetLevel int `json:"petLevel,omitempty" bson:"petLevel,omitempty"`
PetQualityID int `json:"petQualityId,omitempty" bson:"petQualityId,omitempty"`
}
type AuctionResponse struct {
Realms []struct {
Name string `json:"name"`
Slug string `json:"slug"`
} `json:"realms"`
Auctions []Auctions `json:"auctions"`
}
func (b *Blizzard) RealmAuctionGrabber(realms chan string, db *mgo.Database, wg *sync.WaitGroup) {
defer wg.Done()
for i := range realms {
NewReq, err := http.NewRequest("GET", fmt.Sprintf("%s/auction/data/%s", b.Url, i), nil)
if err != nil {
fmt.Printf("Cannot create new request for realm %s: %s", i, err)
}
// Update the request with the default parameters and grab the files links.
Request := PopulateDefaultParams(NewReq)
log.Debugf("downloading %s auction locations.", i)
Response, err := b.Client.Do(Request)
if err != nil {
fmt.Printf("Error request realm auction data: %s\n", err)
}
defer Response.Body.Close()
Body, err := ioutil.ReadAll(Response.Body)
if err != nil {
fmt.Printf("Error parsing request body: %s\n", err)
}
var AuctionResp lib.AuctionAPI
err = json.Unmarshal(Body, &AuctionResp)
if err != nil {
fmt.Printf("Error marshalling auction repsonse body: %s\n", err)
}
for _, x := range AuctionResp.Files {
NewDataReq, err := http.NewRequest("GET", x.URL, nil)
if err != nil {
log.Error(err)
}
AuctionResponse, err := b.Client.Do(NewDataReq)
if err != nil {
fmt.Printf("Error request realm auction data: %s\n", err)
}
defer Response.Body.Close()
AuctionBody, err := ioutil.ReadAll(AuctionResponse.Body)
if err != nil {
fmt.Printf("Error parsing request body: %s\n", err)
}
var AuctionData lib.AuctionResponse
err = json.Unmarshal(AuctionBody, &AuctionData)
// grab all the current records, then perform an Upsert!
var existing []lib.Auctions
col := db.C(i)
err = col.Find(nil).All(&existing)
if err != nil {
log.Error(err)
}
log.Infof("performing bulk upsert for %s", i)
auctionData, err := bson.Marshal(AuctionData.Auctions)
if err != nil {
log.Error("error marshalling bson: %s", err)
}
existingData, _ := bson.Marshal(existing)
bulk := db.C(i).Bulk()
bulk.Upsert(existingData, auctionData)
_, err = bulk.Run()
if err != nil {
log.Error("error performing upsert! error: ", err)
}
}
}
}
当我致电bulk.Upsert(existingData,auctionData)
时,事情很好。但是,当我拨打bulk.Run()
时,我收到了此错误消息:
{"level":"error","msg":"error performing upsert! error: wrong type for 'q' field, expected object, found q: BinData(0, 0500000000)","time":"2016-07-09T16:53:45-07:00"}
我假设这与我在Auction
结构中进行BSON标记的方式有关,但我不确定,因为这是我第一次这样做。与MongoDB合作过。现在,数据库中没有集合,
错误消息是否与BSON标记有关,我该如何解决?
答案 0 :(得分:1)
不知道这是否仍然存在。这是代码:
package main
import (
"gopkg.in/mgo.v2"
"log"
"io/ioutil"
"encoding/json"
"gopkg.in/mgo.v2/bson"
)
type Auctions struct {
Auc int `json:"auc" bson:"_id"`
Owner string `json:"owner" bson:"owner"`
}
type AuctionResponse struct {
Auctions []Auctions `json:"auctions"`
}
func main() {
session, err := mgo.Dial("mongodb://127.0.0.1:27017/aucs")
if err != nil {
panic(err)
}
defer session.Close()
session.SetMode(mgo.Monotonic, true)
db := session.DB("aucs")
var AuctionData AuctionResponse
AuctionBody, _ := ioutil.ReadFile("auctions.json")
err = json.Unmarshal(AuctionBody, &AuctionData)
log.Println("performing bulk upsert for %s", "realm")
bulk := db.C("realm").Bulk()
for _, auc := range AuctionData.Auctions {
bulk.Upsert(bson.M{"_id": auc.Auc}, auc)
}
_, err = bulk.Run()
if err != nil {
log.Panic("error performing upsert! error: ", err)
}
}
我已经做了一些更改,以检查我是否对真实数据是正确的,但我希望不难理解发生了什么。现在让我解释一下Mongo的一部分。
existing
个文档。在更新或插入特别是大型数据库之前请求所有现有文档会很奇怪。mgo
' upsert
函数需要两个参数:
selector
文档(我更倾向于将其视为关于SQL的WHERE
条件)document
您实际拥有并且如果选择器查询失败将插入到数据库中upsert
,可以使用selector - document
个无限数量的bulk.Upsert(sel1, doc1, sel2, doc2, sel3, doc3)
对推送一个请求,例如upsert
,但在您的情况下,没有必要使用此功能。 selector
仅影响单个文档,因此即使您upsert
符合多个文档,也只会首先更新。换句话说,INSERT ... ON DUPLICATE KEY UPDATE
更类似于MySQL UPDATE ... WHERE
而不是upsert
。在您的情况下(使用唯一拍卖ID),单INSERT INTO realm (auc, owner) VALUES ('1', 'Hogger') ON DUPLICATE KEY UPDATE owner = 'Hogger';
看起来像MySQL查询:
bulk
使用SELECT T1.comp, T1,code, T1 date
FROM T1
,我们可以在循环中进行多次upsert,然后立即运行它们。