web-dev-qa-db-ja.com

文字列からObjectIdへの_idフィールドでのMongodb Join

私は2つのコレクションを持っています

  1. ユーザー

             {
                 "_id" : ObjectId("584aac38686860d502929b8b"),
                 "name" : "John"
             }
    
  2. 役割

     {
         "_id" : ObjectId("584aaca6686860d502929b8d"),
         "role" : "Admin",
         "userId" : "584aac38686860d502929b8b"  
     }
    

serId(in roleコレクション)-_ id(in serコレクション)に基づいてこれらのコレクションに参加したい。

私は以下のクエリを試しました:

db.role.aggregate(
{
   $lookup:
   {
       from: 'user',
       localField: 'userId',
       foreignField: '_id',
       as: 'output'
   }
}
);

これにより、userIdをObjectIdとして保存している限り、期待される結果が得られます。 userIdが文字列の場合、結果はありません。 Ps:試した

foreignField: '_id'.valueOf()

そして

foreignField: '_id'.toString()

。しかし、ObjectId文字列フィールドに基づいて一致/結合する運はありません。

任意の助けをいただければ幸いです。

15
Kavya Mugali

これは、MongoDB 3.4以降では不可能です。この機能は既にリクエストされていますが、まだ実装されていません。対応するチケットは次のとおりです。

今のところ、userIdをObjectIdとして保存する必要があります


[〜#〜] edit [〜#〜]

以前のチケットはMongoDB 4.0で修正されました。次のクエリでこれを実現できます。

db.user.aggregate([
  {
    "$project": {
      "_id": {
        "$toString": "$_id"
      }
    }
  },
  {
    "$lookup": {
      "from": "role",
      "localField": "_id",
      "foreignField": "userId",
      "as": "role"
    }
  }
])

結果:

[
  {
    "_id": "584aac38686860d502929b8b",
    "role": [
      {
        "_id": ObjectId("584aaca6686860d502929b8d"),
        "role": "Admin",
        "userId": "584aac38686860d502929b8b"
      }
    ]
  }
]

オンラインで試してください: mongoplayground.net/p/JoLPVIb1OLS

12
felix

$toObjectId mongodbからの集約4.0String idObjectIdに変換します

db.role.aggregate([
  { "$lookup": {
    "from": "user",
    "let": { "userId": "$_id" },
    "pipeline": [
      { "$addFields": { "userId": { "$toObjectId": "$userId" }}},
      { "$match": { "$expr": { "$eq": [ "$userId", "$$userId" ] } } }
    ],
    "as": "output"
  }}
])

または、 $toString mongodbからの集約4.0ObjectIdStringに変換します

db.role.aggregate([
  { "$addFields": { "userId": { "$toString": "$_id" }}},
  { "$lookup": {
    "from": "user",
    "localField": "userId",
    "foreignField": "userId",
    "as": "output"
  }}
])
15
Ashh

前の回答には、「$ toObjectId」の場合にエラーがあると思います。 letステートメントは、関数aggregateが呼び出されるdbコレクション(つまり「ロール」)に適用され、「from」(つまり「ユーザー」)が指すコレクションには適用されません。

db.role.aggregate([
  { "$lookup": {
    "let": { "userObjId": { "$toObjectId": "$userId" } },
    "from": "user",
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$_id", "$$userObjId" ] } } }
    ],
    "as": "userDetails"
  }}
])

または

db.role.aggregate([
  { "$project": { "userObjId": { "$toObjectId": "$userId" } } },
  { "$lookup": {
    "localField": "userObjId",
    "from": "user",
    "foreignField": "$_id",
    "as": "userDetails"
  }}
])

そして

db.user.aggregate([
  { "$project": { "userStrId": { "$toString": "$_id" }}},
  { "$lookup": {
    "localField": "userStrId",
    "from": "role",
    "foreignField": "userId",
    "as": "roleDetails"
  }}
])
0
Gary Wild