如何通过包含 javascript 的 mongo_go_driver 运行聚合查询?

And*_*man 1 javascript aggregate go mongodb

我正在使用 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()}} }
])
Run Code Online (Sandbox Code Playgroud)

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

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

(总的来说,无论如何,我不喜欢这种方法。我希望能够在 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)
Run Code Online (Sandbox Code Playgroud)

如果有一种方法可以将命令作为字符串发送给 Mongo(就像我在 Robo 3T 中输入它一样)并返回一个 *mongo.Cursor,我真的很喜欢它。是否有更好的驱动程序(仍然有人支持)我应该使用它?我需要自己编码吗?

谢谢!

Wan*_*iar 6

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

虽然我知道这不是您用例的首选方法,但这是使用mongo-go-driver v1.0将聚合管道构建为bson.D 的方法:

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)},
            }, 
        },
    }}},  
}
Run Code Online (Sandbox Code Playgroud)

{ $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 } }
]);
Run Code Online (Sandbox Code Playgroud)

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

根据该$match值,您似乎将日期存储为string而不是Date对象。我建议将日期存储为适当的Date对象以获得更好的索引性能。

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

mongo shell 提供了一些方便的方法/类型 ieObjectID()等来构建MongoDB 扩展 JSON。该mongo壳不仅仅是一个JavaScript外壳。

如果您的目标只是评估 JavaScript 表达式,您可以使用 Go (otto) 的 JavaScript 解释器。一个粗略的例子是:

// 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)
Run Code Online (Sandbox Code Playgroud)

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

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

虽然目前不支持 Go,但值得一提的是MongoDB Compass有一个将查询导出到语言的功能。当前版本 (1.15) 支持 Java、Node、C# 和 Python3。希望 Go 会在未来出现。