Как запустить совокупный запрос через mongo_go_driver, в котором есть javascript?

Я использую 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. Есть ли лучший драйвер (который все еще поддерживается кем-то), который я должен использовать вместо этого? Нужно ли мне кодировать свой собственный?

Спасибо!


person Andrew Springman    schedule 08.09.2018    source источник
comment
Вы не можете. Вам нужно найти эквивалентный способ сделать это в Go. В этом JS нет ничего особенного — он просто возвращает значение даты в определенное время в прошлом. Должно быть абсолютно тривиально сделать то же самое без JS.   -  person Flimzy    schedule 08.09.2018
comment
Flimzy: вы абсолютно правы в том, что JS не представляет собой ничего особенного, и я могу заменить его на time.Now().AddDate(0, 0, -1).UTC().Format(time.RFC3339) в golang. Для всех: Чтобы уточнить, к чему я веду, кто-нибудь знает, где я могу найти документацию по базовому API mongodb, который использует драйвер, чтобы я мог определить, доступен ли синтаксический анализатор javascript на этом уровне или только в оболочке mongo ?   -  person Andrew Springman    schedule 09.09.2018
comment
Кроме того, чтобы уточнить, JS был не единственным, что работало в оболочке Robo3T/Mongo и не работало в ParseExtJSONArray. ParseExtJSONArray требует, чтобы все этапы агрегации и функции были заключены в кавычки (а не голые). Есть ли способ для клиентской программы golang запрашивать монго, как оболочку?   -  person Andrew Springman    schedule 09.09.2018
comment
Если ваш запрос: Где мне найти документы MongoDB? вопрос, к сожалению, здесь не по теме, как и запросы ресурсов не по теме. Однако найти документацию по MongoDB API должно быть легко.   -  person Flimzy    schedule 09.09.2018
comment
Справедливо. Я полагаю, что элементы моего вопроса по теме теперь решены, и я перехожу к не по теме. Я отвечу на вопрос тем, что я узнал.   -  person Andrew Springman    schedule 09.09.2018


Ответы (2)


Я не могу понять, как использовать команды Javascript с помощью этого метода.

Хотя я понимаю, что это не предпочтительный метод для вашего варианта использования, вот как построить конвейер агрегации как bson.D с использованием mongo-go-driver v1.0:

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)},
            }, 
        },
    }}},  
}

{ $проект: { "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: (новая дата(Date.now()-1000*60*60*24)).toISOString()}} }

Основываясь на значении $match, похоже, что вы сохраняете дату как string вместо Дата объект. Я бы предложил хранить даты как правильные объекты Date для повышения производительности индекса.

Использование ParseExtJSONArray РАБОТАЕТ, но, в отличие от Mongo Shell, вы не можете включать JS или этапы агрегации без кавычек/операторы выражений

Оболочка mongo предоставляет несколько удобных методов/типов, например ObjectID() и т. д., для создания Расширенный JSON MongoDB. Оболочка mongo — это больше, чем просто оболочка JavaScript.

Если вы хотите просто оценить выражение JavaScript, вы можете использовать интерпретатор JavaScript для Go (otto). Грубый пример:

// 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, например ИдентификаторОбъекта()

Я хочу иметь возможность создавать запросы в Robo 3T и копировать их в свой код так же, как я делаю это с MySQL Workbench и PHP.

Хотя в настоящее время Go не поддерживается, стоит отметить, что MongoDB Compass имеет функцию Экспорт запроса на язык. Текущая версия (1.15) поддерживает Java, Node, C# и Python3. Надеюсь, Go будет в будущем.

person Wan Bachtiar    schedule 10.09.2018
comment
Очень признателен. У меня есть несколько уточняющих вопросов. Первый связан с конвейером агрегации в виде *bson.Document. Как только я создам этот *bson.Array, скажем, я хочу использовать его повторно и просто изменить дату. Есть ли простой способ добраться до него или мне нужно построить итератор и сделать несколько вызовов Lookup()? Не проще ли каждый раз конструировать все целиком? (или собрать *bson.Array из частично построенных частей). - person Andrew Springman; 10.09.2018
comment
Второй вопрос связан с вашим предложением использовать объект Date вместо строки даты. Я не могу поместить ISODate(...) в строку для подхода ParseExtJSONArray. Я узнал, что ISODate(...) экспортируется в {$date:...}, но если я помещу это в строку JSON и попытаюсь сопоставить $match с датой dateTimeGMT.$date, это не сработает. Является ли подход *bson.Document единственным вариантом для работы с объектами даты вместо даты в виде строки? - person Andrew Springman; 10.09.2018
comment
Сделайте это двумя вопросами. - person Andrew Springman; 10.09.2018
comment
1) Обычно вы создаете bson.Document для каждого этапа, затем собираете в один bson.Array перед отправкой в ​​агрегацию. Таким образом, вы можете создать только $match документ вместо всех этапов. - person Wan Bachtiar; 11.09.2018
comment
2) должно работать. ParserExtJSONArray должен понимать расширенный формат JSON $date, не могли бы вы открыть новый вопрос с примерами и опубликовать ссылку здесь. - person Wan Bachtiar; 11.09.2018
comment
Сделаю. Спасибо! - person Andrew Springman; 11.09.2018
comment
Вот оно: stackoverflow.com/questions/52276568/ - person Andrew Springman; 11.09.2018

Использование 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)

С водителем, о котором я спрашивал, вот и ответ.

person Andrew Springman    schedule 09.09.2018