上記のクエリは、User
に「ほぼ」一致するドキュメントを返します ドキュメントですが、各ユーザーの投稿もあります。つまり、基本的に結果は一連のUser
Post
のあるドキュメント 配列またはスライス埋め込み 。
1つの方法は、Posts []*Post
を追加することです。 User
へのフィールド それ自体、そして私たちは完了します:
type User struct {
ID string `bson:"_id"`
Name string `bson:"name"`
Registered time.Time `bson:"registered"`
Posts []*Post `bson:"posts,omitempty"`
}
これは機能しますが、User
を拡張するのは「やり過ぎ」のようです。 Posts
を使用 単一のクエリのためだけに。この道を進むとしたら、User
タイプは、さまざまなクエリに対して多くの「余分な」フィールドで肥大化するでしょう。 Posts
に入力するかどうかは言うまでもありません フィールドにユーザーを保存すると、それらの投稿はUser
内に保存されます。 資料。私たちが望んでいるものではありません。
もう1つの方法は、UserWithPosts
を作成することです。 タイプコピーUser
、およびPosts []*Post
を追加します 分野。言うまでもなく、これは醜くて柔軟性がありません(User
に加えられた変更) UserWithPosts
に反映する必要があります 手動で)。
構造体埋め込みあり
元のUser
を変更する代わりに 、新しいUserWithPosts
を作成する代わりに 「scratch」から入力すると、構造体埋め込み
を利用できます。 (既存のUser
を再利用します およびPost
タイプ)ちょっとしたトリックで:
type UserWithPosts struct {
User `bson:",inline"`
Posts []*Post `bson:"posts"`
}
bson タグの値に注意してください
",inline"
。これは、 bson.Marshal()
に記載されています。
およびbson.Unmarshal()
(マーシャリング解除に使用します):
埋め込みと",inline"
を使用する タグ値、UserWithPosts
タイプ自体は、User
のマーシャリングを解除するための有効なターゲットになります ドキュメントとそのPost []*Post
フィールドは、検索された"posts"
に最適です。 。
使用:
var uwp *UserWithPosts
it := pipe.Iter()
for it.Next(&uwp) {
// Use uwp:
fmt.Println(uwp)
}
// Handle it.Err()
または、すべての結果を1つのステップで取得します:
var uwps []*UserWithPosts
err := pipe.All(&uwps)
// Handle error
UserWithPosts
の型宣言 ローカル宣言である場合とそうでない場合があります。他の場所で必要ない場合は、集計クエリを実行および処理する関数のローカル宣言にすることができるため、既存の型と宣言が肥大化することはありません。再利用したい場合は、パッケージレベル(エクスポートまたは非エクスポート)で宣言し、必要な場所で使用できます。
集計の変更
もう1つのオプションは、MongoDBの $replaceRoot
を使用することです。
結果ドキュメントを「再配置」するため、「単純な」構造体がドキュメントを完全にカバーします。
// Query users with their posts:
pipe := collUsers.Pipe([]bson.M{
{
"$lookup": bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "userID",
"as": "posts",
},
},
{
"$replaceRoot": bson.M{
"newRoot": bson.M{
"user": "$$ROOT",
"posts": "$posts",
},
},
},
})
この再マッピングにより、結果ドキュメントは次のようにモデル化できます。
type UserWithPosts struct {
User *User `bson:"user"`
Posts []*Post `bson:"posts"`
}
これは機能しますが、posts
であることに注意してください すべてのドキュメントのフィールドがサーバーから2回フェッチされます。1回はposts
として取得されます。 返されたドキュメントのフィールド、およびuser
のフィールドとして1回;マップ/使用はしませんが、結果ドキュメントに存在します。したがって、このソリューションを選択した場合、user.posts
フィールドを削除する必要があります。例: $project
を使用 ステージ:
pipe := collUsers.Pipe([]bson.M{
{
"$lookup": bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "userID",
"as": "posts",
},
},
{
"$replaceRoot": bson.M{
"newRoot": bson.M{
"user": "$$ROOT",
"posts": "$posts",
},
},
},
{"$project": bson.M{"user.posts": 0}},
})