2016-08-04 8 views
1

У меня есть структура db, определенная следующим образом.Go - mgo, извлекать все вложенные поля из коллекции

{ 
    name: "Jane", 
    films: [ 
     { 
      title: "The Shawshank Redemption", 
      year: "1994" 
     }, 
     { 
      title: "The Godfather", 
      year: "1972" 
     } 
    ] 
}, 
{ 
    name: "Jack", 
    films: [ 
     { 
      title: "12 Angry Men", 
      year: "1957" 
     }, 
     { 
      title: "The Dark Knight", 
      year: "2008" 
     } 
    ] 
} 

Я хочу вернуть кусочек всех фильмов - []Film и, если это возможно, в другом запросе кусочек всех названий - []string из коллекции. Я могу вытащить всю коллекцию и извлечь соответствующие данные в логике приложения, но можно ли достичь этого в запросе? Я попытался работать с методом Select(), что-то вроде этого: c.Find(nil).Select(<various conditions>).All(&results), но я не был успешным.

ответ

1

Я думаю, что это один из самых популярных вопросов на теге mongo. И я должен сказать, если вам нужно, чтобы вы делали что-то не так, и, возможно, вам следует использовать СУРБД вместо Монго, так как падение производительности в подобных запросах приведет к аннулированию всей прибыли от функций Mongo, таких как схемы, документы «все-в-одном» и т. Д. ..

В любом случае, ответ прост - вы не можете получить список фильмов, как хотите. Mongo's find может возвращать только полный или частичный документ верхнего уровня. Я имею в виду лучший результат вы можете получить с помощью db.collection.find({}, {'films': 1}) запроса является список как

{ 
    films: [ 
     { 
      title: "The Shawshank Redemption", 
      year: 1994 
     }, 
     { 
      title: "The Godfather", 
      year: 1972 
     } 
    ] 
}, 
{ 
    films: [ 
     { 
      title: "12 Angry Men", 
      year: 1957 
     }, 
     { 
      title: "The Dark Knight", 
      year: 2008 
     } 
    ] 
} 

Не то, что вы expectied, верно?

Единственный способ получить массив как

{ 
    title: "The Shawshank Redemption", 
    year: 1994 
}, 
{ 
    title: "The Godfather", 
    year: 1972 
}, 
{ 
    title: "12 Angry Men", 
    year: 1957 
}, 
{ 
    title: "The Dark Knight", 
    year: 2008 
} 

является использование aggregation.

Основной запрос Монго, чтобы получить массив фильмов

db.collection.aggregate([{ 
    $unwind: '$films' 
}, { 
    $project: { 
     title: '$films.title', 
     year: '$films.year' 
    } 
}]) 

код Go для этого запроса

package main 

import (
    "gopkg.in/mgo.v2" 
    "gopkg.in/mgo.v2/bson" 
    "fmt" 
) 

func main() { 
    session, err := mgo.Dial("mongodb://127.0.0.1:27017/db") 

    if err != nil { 
     panic(err) 
    } 
    defer session.Close() 
    session.SetMode(mgo.Monotonic, true) 

    c := session.DB("db").C("collection") 

    pipe := c.Pipe(
     []bson.M{ 
      bson.M{ 
       "$unwind": "$films", 
      }, 
      bson.M{ 
       "$project": bson.M{ 
        "title": "$films.title", 
        "year": "$films.year", 
       }, 
      }, 
     }, 
    ) 
    result := []bson.M{} 
    err = pipe.All(&result) 
    fmt.Printf("%+v", result) // [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Godfather year:1972] map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:12 Angry Men year:1957] map[year:2008 _id:ObjectIdHex("57a2ed6f40ce01187e1c9165") title:The Dark Knight]] 
} 

Если вам нужны дополнительные условия для выбора документов верхнего уровня кода будет

pipe := c.Pipe(
    []bson.M{ 
     bson.M{ 
      "$match": bson.M{ 
       "name": "Jane", 
      }, 
     }, 
     bson.M{ 
      "$unwind": "$films", 
     }, 
     bson.M{ 
      "$project": bson.M{ 
       "title": "$films.title", 
       "year": "$films.year", 
      }, 
     }, 
    }, 
) 
// result [map[_id:ObjectIdHex("57a2ed6640ce01187e1c9164") title:The Shawshank Redemption year:1994] map[title:The Godfather year:1972 _id:ObjectIdHex("57a2ed6640ce01187e1c9164")]] 

Для фильтров необходимо использовать следующий запрос

pipe := c.Pipe(
    []bson.M{ 
     bson.M{ 
      "$unwind": "$films", 
     }, 
     bson.M{ 
      "$project": bson.M{ 
       "title": "$films.title", 
       "year": "$films.year", 
      }, 
     }, 
     bson.M{ 
      "$match": bson.M{ 
       "year": bson.M{ 
        "$gt": 2000, 
       }, 
      }, 
     }, 
    }, 
) 
// result [map[_id:ObjectIdHex("57a2ed6f40ce01187e1c9165") year:2008 title:The Dark Knight]] 

Проблема с агрегацией - это простой факт, что большая часть операций агрегации не использует индексы и может быть медленной в больших коллекциях. Вот почему я предложил вам подумать о РСУБД, которая может быть лучшим выбором, если вам нужно много скоплений.

И нет никакого способа, чтобы получить []string от mgo, как она всегда возвращает bson.M (или []bson.M), который является map[string]interface{}.

+0

Большое спасибо за подробный ответ. Возможно, вы правы, и мне будет лучше с Postgres. –

+0

@curious_gudleif умный выбор. –

 Смежные вопросы

  • Нет связанных вопросов^_^