1. ホーム
  2. mongodb

[解決済み] MongoDB: 配列のフィールドに要素があるかどうかを調べるには?

2023-06-28 10:34:28

質問

2つのコレクションがあります。 最初のコレクションは、学生を含んでいます。

{ "_id" : ObjectId("51780f796ec4051a536015cf"), "name" : "John" }
{ "_id" : ObjectId("51780f796ec4051a536015d0"), "name" : "Sam" }
{ "_id" : ObjectId("51780f796ec4051a536015d1"), "name" : "Chris" }
{ "_id" : ObjectId("51780f796ec4051a536015d2"), "name" : "Joe" }

2番目のコレクションにはコースが含まれています。

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
        "name" : "CS 101",
        "students" : [
                ObjectId("51780f796ec4051a536015cf"),
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d2")
        ]
}
{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc5"),
        "name" : "Literature",
        "students" : [
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d0"),
                ObjectId("51780f796ec4051a536015d2")
        ]
}
{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
        "name" : "Physics",
        "students" : [
                ObjectId("51780f796ec4051a536015cf"),
                ObjectId("51780f796ec4051a536015d0")
        ]
}

各コースドキュメントには students 配列が含まれます。これはコースに登録された学生のリストを持っています。 学生がウェブページでコースを閲覧する場合、すでにコースに登録されているかどうか確認する必要があります。 それを行うために courses コレクションが学生のためにクエリされるとき、私たちは以下のことを見つける必要があります。 students 配列がすでに学生の ObjectId を含んでいるかどうかを調べる必要があります。 検索クエリのプロジェクションで、生徒の ObjectId から students 配列がある場合のみ?

elemMatch演算子ができないか試してみましたが、サブドキュメントの配列向けです。 集計フレームワークを使用できることは理解していますが、この場合、それは過剰になるように思われます。 集約フレームワークはおそらく単一の検索クエリほど高速ではないでしょう。 返されたドキュメントがこのようなフォームになるように、コースコレクションにクエリを実行する方法はありますか?

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc4"),
        "name" : "CS 101",
        "students" : [
                ObjectId("51780f796ec4051a536015d0"),
        ]
}

どのように解決するのですか?

[ 編集 最近のバージョンで可能になったことに基づく] 。

[更新された回答】以下の方法で、すでに登録されている場合のみ、クラス名と学生IDを取得することができます。

db.student.find({},
 {_id:0, name:1, students:{$elemMatch:{$eq:ObjectId("51780f796ec4051a536015cf")}}})

と入力すれば、期待通りの結果が返ってきます。

{ "name" : "CS 101", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }
{ "name" : "Literature" }
{ "name" : "Physics", "students" : [ ObjectId("51780f796ec4051a536015cf") ] }

[当初の回答] 現在、あなたがやりたいことはできません。 生徒がオブジェクトとして配列に格納されていれば、このようなことが可能になるため、これは残念なことです。 実際、あなたがObjectId()だけを使用していることに少し驚きました。 常に を使用すると、特定のコースに登録されている学生のリストを表示したい場合、学生を検索する必要があります (最初に ID のリストを検索してから、学生コレクションで名前を検索します - 1 つのクエリではなく 2 つのクエリです!)。

(例として) IDと名前をこのようなコース配列に保存していたとします。

{
        "_id" : ObjectId("51780fb5c9c41825e3e21fc6"),
        "name" : "Physics",
        "students" : [
                {id: ObjectId("51780f796ec4051a536015cf"), name: "John"},
                {id: ObjectId("51780f796ec4051a536015d0"), name: "Sam"}
        ]
}

その時のクエリーは、単純に

db.course.find( { }, 
                { students : 
                    { $elemMatch : 
                       { id : ObjectId("51780f796ec4051a536015d0"), 
                         name : "Sam" 
                       } 
                    } 
                } 
);

もしその学生がCS101にしか在籍していなかったら......取り返しがつかないことになります。

{ "name" : "Literature" }
{ "name" : "Physics" }
{
    "name" : "CS 101",
    "students" : [
        {
            "id" : ObjectId("51780f796ec4051a536015cf"),
            "name" : "John"
        }
    ]
}