如何通过包含JavaScript的mongo_go_driver运行汇总查询?

时间:2018-09-08 11:54:09

标签: javascript mongodb go aggregate

我正在使用mongo-go-driver(https://godoc.org/github.com/mongodb/mongo-go-driver/mongo),并且正在尝试做

db.getCollection('mycollection').aggregate([
    { $lookup: {
        from: "anothercollection",
        localField: "_id",
        foreignField: "foreignID",
        as: "matched_docs"
    }},
    { $match: { "matched_docs": { $eq: [] } } },
    { $project: { "matched_docs": 0 } },
    { $match: {"dateTimeGMT":{$lt: (new Date(Date.now()-1000*60*60*24)).toISOString()}} }
])

我不知道如何使用此方法放置Javascript命令。

pipeline := bson.NewArray(
    bson.VC.DocumentFromElements(
        bson.EC.SubDocumentFromElements( 
        //yada, yada, yada...
cursor, err := collection.Aggregate(ctx, pipeline)

(总的来说,我还是不喜欢这种方法。我希望能够在Robo 3T中设计查询并将其复制到我的代码中,就像使用MySQL Workbench和PHP一样)

此方法在管道中产生一个空的* bson.Array

pipelineJSON := `[
    { $lookup: {
        from: "anothercollection",
        localField: "_id",
        foreignField: "interactionID",
        as: "matched_docs"
    }},
    { $match: { "matched_docs": { $eq: [] } } },
    { $project: { "matched_docs": 0 } },
    { $match: {"dateTimeGMT":{$lt: (new Date(Date.now()-1000*60*60*24)).toISOString()}} }
]`
pipeline, err = bson.ParseExtJSONArray(pipelineJSON)

如果有一种方法可以将字符串形式的命令发送给Mongo(例如我在Robo 3T中键入命令)并获得* mongo.Cursor,我将非常喜欢它。有没有我应该使用的更好的驱动程序(仍然有人支持)?我需要自己编写代码吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

使用ParseExtJSONArray确实可以工作,但是与Mongo Shell不同,您不能包含JS或未引用的聚合阶段/表达式运算符。请注意,用于比较的ISO日期是用golang计算的,聚合阶段和聚集表达式运算符已用引号引起来。

pipelineJSON := fmt.Sprintf(`[
    { "$lookup": {
        "from": "another_collection",
        "localField": "_id",
        "foreignField": "interactionID",
        "as": "matched_docs"
    }},
    { "$match": { "matched_docs": { "$eq": [] } } },
    { "$project": { "matched_docs": 0 } },
    { "$match": {"dateTimeGMT":{"$lt": "%s"}} }
]`, time.Now().AddDate(0, 0, -1).UTC().Format(time.RFC3339))
pipeline, err = bson.ParseExtJSONArray(pipelineJSON)

我问的司机就是答案。

答案 1 :(得分:2)

  

我不知道如何使用这种方法来放置Javascript命令。

尽管我知道这不是您的用例的首选方法,但这是如何使用aggregation pipeline v1.0将bson.D构造为mongo-go-driver的方法:

pipeline := mongo.Pipeline{
    {{"$lookup", bson.D{
        {"from", "tour"}, 
        {"localField", "_id"}, 
        {"foreignField", "foreignID"}, 
        {"as", "matched_docs"},
    }}},
    {{"$match", bson.D{
        {"matched_docs", bson.D{
            {"$eq", bson.A{}}},
        }, 
    }}},
    {{"$project", bson.D{
        {"matched_docs", 0}, 
    }}},        
    {{"$match", bson.D{
        {"dateTimeGMT", bson.D{
            {"$lt", time.Now().AddDate(0, 0, -1).UTC().Format(time.RFC3339)},
            }, 
        },
    }}},  
}
  

{$ project:{“ matched_docs”:0}},

您也可以将两个$match合并到一个管道阶段,然后在末尾附加$project。例如:

db.collection.aggregate([
    { "$lookup":{
        "from":"anothercollection",
        "localField":"_id",
        "foreignField":"foreignID",
        "as":"matched_docs"}
    }, 
    { "$match": { "matched_docs": { "$eq": [] }, 
                  "datetimegmt": { "$lt": (new Date(Date.now()-1000*60*60*24)).toISOString() } 
                } 
    }, 
    { "$project": { "matched_docs": 0 } }
]);
  

{$ match:{“ dateTimeGMT”:{$ lt:(new Date(Date.now()-1000 * 60 * 60 * 24))。toISOString()}}}

基于$match值,似乎您将日期存储为string而不是Date对象。我建议将日期存储为适当的Date对象,以提高索引性能。

  

使用ParseExtJSONArray确实可以,但与Mongo Shell不同,您不能包含JS或未引用的聚合阶段/表达式运算符

mongo shell提供了一些方便的方法/类型,即ObjectID()等来构造MongoDB Extended JSONmongo Shell不仅仅是一个JavaScript Shell。

如果您只想评估JavaScript表达式,则可以将JavaScript解释器用于Go(底部)。大概的例子是:

// Note the unquoted fields, as JSON is JavaScript native. 
raw := `[
    { "$lookup": {
        from: "anothercollection",
        localField: "_id",
        foreignField: "foreignID",
        as: "matched_docs"
    }},
    { $match: { "matched_docs": { $eq: [] },
                "dateTimeGMT":{$lt: (new Date(Date.now()-1000*60*60*24)).toISOString() }, 
              }
    },
    { $project: { "matched_docs": 0 } },
]`
vm := otto.New()
// Evaluate JS expression
jsvalue, err := vm.Eval(raw)

// Export to Go interface{}
output, err := jsvalue.Export()

// Convert interface{} to bson.Document bytes 
bsonbytes, err := bson.Marshal(output)

// Convert bson.Document bytes to bson.Document
pipeline, err := bson.UnmarshalDocument(bsonbytes)

请注意,如上所述,有些对象无法被普通的JavaScript解释器识别,例如ObjectId()

  

我希望能够在Robo 3T中设计查询并将其复制到我的代码中,就像使用MySQL Workbench和PHP一样

尽管当前不支持Go,但值得一提的是MongoDB Compass具有Export Query to Language的功能。当前版本(1.15)支持Java,Node,C#和Python3。希望Go会在将来。