Mongoose объединяет две коллекции и получает ссылочные данные в двух свойствах

#node.js #mongodb #mongoose

#node.js #mongodb #mongoose

Вопрос:

Я выполняю простую функцию follow friend.

Пожалуйста, смотрите Мои коды ниже:

Следующая схема:

 {
 "userId": { type: String },
 "followers": [{ "followerId": type: String }],
 "followings": [{ "followingId": type: String }], 
}
  

Схема пользователя:

 {
 "fullName": { type: String } 
}
  

Примечание: у пользователя 8 есть 1 подписчик и 2 подписчика.

Теперь мой ожидаемый результат должен быть таким:

         "userId": 8,
        "followers": [
            {
                "followerId": 4,
                "fullName": "Rose Marriott",
            },
            {
                "followerId": 5,
                "fullName": "James Naismith",
            }
        ],
        "followings": [
            {
                "followingId": 1,
                "fullName": "Russell Oakham",
            },
            {
                "followingId": 5,
                "fullName": "James Naismith",
            }
        ]
  

Это то, что я пробовал до сих пор:

  db.followings.aggregate([
 { $unwind: "$followers" },
    {
        $lookup: {
            from: "users",
            localField: "followers.followerId",
            foreignField: "_id",
            as: "users"
        }
    },
    { 
        $addFields: 
        { 
            users: { $arrayElemAt: ["$users", 0] },
        },
    },
    { $unwind: "$followings" },
    {
        $lookup: {
          from: "users",
          localField: "followings.followingId",
          foreignField: "_id",
          as: "users2"
        }
    },
    { 
        $addFields: 
        { 
            users2: { $arrayElemAt: ["$users2", 0] },
        },
    },
    { $match: {"userId": mongoose.Types.ObjectId(userId) } },
    {
        $group: {
            _id: "$_id",
            userId: { $first: "$userId" },
            followers: {
                $push: {
                    followerId: "$followers.followerId",
                    fullName: "$users.fullName",
                }
            },
            followings: {
                $push: {
                    followingId: "$followings.followingId",
                    fullName: "$users2.fullName",
                }
            }
        }
      }
  ]);
  

Но я получаю 2 подписчика и 2 подписчика. Интересно, что вызывает эту проблему. Ценю любую помощь. Спасибо!

Ответ №1:

Вы можете попробовать,

  • $addFields чтобы создать уникальный массив, вызываемый userIds как массивами followers , так и followings $setUnion для получения уникальных идентификаторов,
  • $lookup с помощью коллекции пользователей
  • $project для отображения полей,
    • followers получить полное имя, $map для итерации цикла followers и получить имя followerId из массива пользователей, используя $reduce и $cond
    • followings получить полное имя, $map для итерации цикла followings и получить имя followingId из массива пользователей, используя $reduce и $cond
 db.followings.aggregate([
  {
    $addFields: {
      userIds: {
        $setUnion: [
          {
            $map: {
              input: "$followers",
              in: "$$this.followerId"
            }
          },
          {
            $map: {
              input: "$followings",
              in: "$$this.followingId"
            }
          }
        ]
      }
    }
  },
  {
    $lookup: {
      from: "users",
      localField: "userIds",
      foreignField: "_id",
      as: "users"
    }
  },
  {
    $project: {
      userId: 1,
      followers: {
        $map: {
          input: "$followers",
          as: "f",
          in: {
            $mergeObjects: [
              "$$f",
              {
                fullName: {
                  $reduce: {
                    input: "$users",
                    initialValue: "",
                    in: {
                      $cond: [
                        { $eq: ["$$this._id", "$$f.followerId"] },
                        "$$this.fullName",
                        "$$value"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      },
      followings: {
        $map: {
          input: "$followings",
          as: "f",
          in: {
            $mergeObjects: [
              "$$f",
              {
                fullName: {
                  $reduce: {
                    input: "$users",
                    initialValue: "",
                    in: {
                      $cond: [
                        { $eq: ["$$this._id", "$$f.followingId"] },
                        "$$this.fullName",
                        "$$value"
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])
  

Игровая площадка

Комментарии:

1. Привет, спасибо за это! У меня есть еще один вопрос. Как мы можем добавить две дополнительные коллекции, такие как изображения и лайки, и отображать изображение пользователя и лайки в массивах подписчиков и подписчиков?

Ответ №2:

при работе с отношениями в Mongoose вы должны создать отношения на основе уникального идентификатора, а затем ссылаться на документ. В вашем случае это было бы:

 followingSchema = new mongoose.Schema({
    {
     "followers": [{type: mongoose.Schema.types.ObjectId, ref="User"}],
     "followings": [{type: mongoose.Schema.types.ObjectId, ref="User"}], 
    }
})

userSchema = new mongoose.Schema({
    fullname: String,
})
  

имейте в виду, что идентификатор пользователя будет автоматически создан Mongoose с полем с именем _id . итак, конечным результатом создания новых следующих документов будет:

 {
    _id: "klajdsfñalkdjf" //random characters created by mongoose,
    followers: ["adfadf134234", "adfadte345"] //same as before, these are Ids of the users randomly generated by mongoose
    followers: ["adfadf134234", "adfadte345"] 
}

{
 _id: adfadf134234,
 fullName: "alex",
}
  

теперь, поскольку нам не нужно иметь случайное число в качестве информации в полях following и followers в следующем объекте, теперь мы можем использовать метод .populate(), который можно использовать над самим документом для преобразования этих идентификаторов в фактическую информацию. Подробнее об этом здесь: документация mongoose

наш конечный результат будет примерно таким:

 {
    _id: "añfakdlsfja",
    followers : [{_id: "adlfadsfj", fullName: "alex"}],
    following : [{_id: "adfadfad" , fullName: "other"}, {_id: "dagadga", fullName: "another"}]
}