MongoDB中类似JOIN操作的模式结构与Mongoose

rryofs0p  于 2023-11-17  发布在  Go
关注(0)|答案(1)|浏览(111)

我正在使用MongoDB开发一个NodeJS应用程序,我希望使用Mongoose复制SQL INNER JOIN的行为。我尝试了几个教程和方法,但没有得到想要的结果。我有以下模式设置:

const domainSchema = new mongoose.Schema({
  domain: {
    type: String,
    required: true,
  },
  portfolioId: {
    type: mongoose.Schema.Types.ObjectId, // Refers to an Object ID in the portfolioSchema
    required: true,
    ref: 'Portfolio'
  },
});

const portfolioSchema = new mongoose.Schema({
  portfolioName: {
    type: String,
    required: true,
  },
  userIds: {
    type: mongoose.Schema.Types.ObjectId, // Refers to an Object ID in the userSchema
    required: true,
    ref: 'User'
  }
});

const userSchema = new mongoose.Schema({
  emailAddress: {
    type: String,
    required: true,
  },
  // Other user fields...
});

字符串
我已经用引用ID构建了我的模式,假设这是你在Mongoose中设置关系的方式。只给出用户的ID,我的目标是获取与该用户关联的所有投资组合以及每个投资组合中的域。这种模式结构适合这个目的吗?
如果有人能指导我具体的MongoDB和NodeJS代码来执行此操作,我将不胜感激。谢谢!

qyzbxkaa

qyzbxkaa1#

在mongoose中,你可以使用Model.populate()来执行从一个集合到另一个集合的查找。这与SQL中的左连接同义(但不完全相同)。populate方法将把文档中所有引用的ObjectId值替换为另一个集合中相应的文档。
在这个例子中:

const Domain = mongoose.model("Domain", domainSchema);
const Portfolio = mongoose.model("Portfolio", portfolioSchema);
const domains = await Domain.find().populate({path: 'portfolioId', model: Portfolio});

字符串
const domains现在将包含所有Domain文档,其中包含所有Portfolio文档,而不仅仅是它们的ID。
popluale的问题是,你不能根据子文档过滤父文档。所以你不能将populatePortfolio转换为Domain,然后删除没有你想要的PortfolioDomain结果。你需要使用aggregate
但是,您似乎是从User._id值开始的,这意味着您可以轻松地查询portfolios集合,但是您必须对domains集合执行另一个数据库查询,以便从以前的结果中找到匹配的portfolioId
根据您当前的Schema设计,我的建议是在Domain模型上执行aggregate查询。
给定一个User文档,其中包含以下_id

{ _id: ObjectId("650ecb80507561a33ce927a3"), emailAddress:"[email protected]"}


以下查询将返回所需的结果:

const documents = await Domain.aggregate([
  {
    "$lookup": {
      "from": "portfolios",
      "localField": "portfolioId",
      "foreignField": "_id",
      "as": "portfolioId"
    }
  },
  {
    "$lookup": {
      "from": "users",
      "localField": "portfolioId.userIds",
      "foreignField": "_id",
      "as": "userIds"
    }
  },
  {
    "$match": {
      "portfolioId.userIds": ObjectId("650ecb80507561a33ce927a3")
    }
  }
])


请参阅HERE以获取工作示例。

编辑

或者,如果你能够重新构建你的schema,那么你可以添加一个Domain引用到你的Portfolio schema,这将允许你搜索portfolios集合。像这样更新你的portfolioSchema

const portfolioSchema = new mongoose.Schema({
  portfolioName: {
    type: String,
    required: true,
  },
  userIds: {
    type: mongoose.Schema.Types.ObjectId, // Refers to an Object ID in the userSchema
    required: true,
    ref: 'User'
  },
  domainId: {
    type: mongoose.Schema.Types.ObjectId, // Refers to an Object ID in the domainSchema
    required: true,
    ref: 'Domain'
  },
});


现在你可以像这样使用Model.populate

const Domain = mongoose.model('Domain', domainSchema);
const User = mongoose.model('User', userSchema);
const Portfolio = mongoose.model('Portfolio', portfolioSchema); 
const portfolios = await Portfolio.find({
      userIds: ObjectId("650ecb80507561a33ce927a3")
   }).populate({
      path: 'userIds', 
      model: User
   }).populate({
      path: 'domainId', 
      model: Domain
   });

相关问题