🔬

【MongoDB】抽出条件にlookupで結合した先のコレクションを含める

2021/11/02に公開

概要

以前に【MongoDB】lookupで結合した先のコレクションの結果をsortしたりlimitをかけてみるの記事で、コレクションの結合機能であるlookupの機能を紹介しました。
今回はそのlookupで、結合した先のコレクションを抽出条件に含める実装を紹介します。(Golangで実装しています)

やりたいこと

まず取得したい結果は、以下のような構造を想定します。

type ItemResponse struct {
  ID              string            `json:"_id" bson:"_id"`
  Name            string            `json:"name" bson:"name"`
  Detail          string            `json:"detail" bson:"detail"`
  ShopID          string            `json:"shop_id" bson:"shop_id"`
  ShopName        string            `json:"shop_name" bson:"shop_name"`
}

結合元のコレクションはitemとし、以下の通りshop_idを持つものとします。

type Item struct {
  ID              string            `json:"_id" bson:"_id"`
  Name            string            `json:"name" bson:"name"`
  Detail          string            `json:"detail" bson:"detail"`
  ShopID          string            `json:"shop_id" bson:"shop_id"`
}

結合先のコレクションshopでショップの情報を保持しているものとします。

type Shop struct {
  ID              string            `json:"_id" bson:"_id"`
  Name            string            `json:"name" bson:"name"`
}

今回はキーワード検索を想定し、itemnameもしくはshopsnameのいずれかに、マッチしているドキュメントを抽出するものとします。

実装サンプル

方針としてはlookupで結合した後に、一度shopをunwindし、その後に抽出条件を設定していきます。Select with sub queryの記事も参考になると思います。

sample.go
// 接続処理は省略・・・
col := c.Database(os.Getenv("DB_NAME")).Collection("item")

// lookupでの結合
lookUpStage := bson.D{{Key: "$lookup", Value: bson.D{
  {Key: "from", Value: "shop"},
  {Key: "localField", Value: "shop_id"},
  {Key: "foreignField", Value: "_id"},
  {Key: "as", Value: "shop"},
}}}
// shopをunwindする
unwindStage := bson.D{{Key: "$unwind", Value: "$shop"}}
// 取得項目の指定
projectStage := bson.D{{Key: "$project", Value: bson.D{
  {Key: "_id", Value: 1},
  {Key: "name", Value: 1},
  {Key: "detail", Value: 1},
  {Key: "shop_id", Value: 1},
  {Key: "shop.name", Value: 1},
}}}
// 抽出条件
matchStage := bson.D{{Key: "$match", Value: bson.D{{Key: "$or", Value: bson.A{
  bson.M{"name": bson.D{{Key: "$regex", Value: primitive.Regex{Pattern: "検索ワード", Options: "i"}}}},
  bson.M{"shop.name": bson.D{{Key: "$regex", Value: primitive.Regex{Pattern: "検索ワード", Options: "i"}}}},
}}}}}

// クエリの実行
pipeLine := mongo.Pipeline{lookupStage, unwindStage, projectStage, matchStage}
cur, err := col.Aggregate(context.Background(), pipeLine)
// 結果のデコード処理は省略・・

Discussion