具有一对多关系的Mongoose文档引用

时间:2016-01-25 05:43:00

标签: node.js mongodb mongoose mongodb-query mongoose-schema

我正在为新项目设计数据库结构,我对MongoDB很新,显然是Mongoose。

我已经阅读了Mongooses population文档,其中它与一对多关系,一个Person文档到许多Story文档,但是混淆的部分我是Story文档引用它所属的Person文档的地方而不是Person模式,它设置了所以它有一个Story文档的数组&# 39;拥有'

我设置了与此非常相似的东西。但我一直认为创建新的Story文档以获得Person文档ID会更容易。但也许这只是因为我更熟悉使用连接的MySQL关系。

如果这是最好的方法(并且我确定它是,因为它在文档中),当创建新的Story文档时,最新的方法是更新数组它所属的相关People文档中的故事?我查看但无法找到更新现有文档的任何示例,以添加对其他文档的引用(或删除它们)

我确信这是一个我忽略的简单解决方案,但任何帮助都会很棒。谢谢!

5 个答案:

答案 0 :(得分:37)

请参阅population,此处从Mongoose中提取示例。

var mongoose = require('mongoose')
, Schema = mongoose.Schema

var personSchema = Schema({
  _id     : Schema.Types.ObjectId,
  name    : String,
  age     : Number,
  stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
  _creator : { type: Schema.Types.ObjectId, ref: 'Person' },
  title    : String,
  fans     : [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});

var Story  = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);

所以关于Story模型的示例在Person._id中存储了相关的Story._creator。当您找到Story的文档时,可以使用populate()方法定义要同时检索的Person模型中的哪个属性,例如:

Story.findOne({_id: 'xxxxxxx'}).populate('person', 'name age').exec(function(err, story) {
  console.log('Story title: ', story.title);
  console.log('Story creator', story.person.name);
});

我相信这就是你要找的。或者,您可以改为使用nested collections

答案 1 :(得分:6)

正如population docs所述

var aaron = new Person({ _id: 0, name: 'Aaron', age: 100 });

aaron.save(function (err) {
  if (err) return handleError(err);

  var story1 = new Story({
    title: "Once upon a timex.",
    _creator: aaron._id    // assign the _id from the person
  });

  story1.save(function (err) {
    if (err) return handleError(err);
    // thats it!
  });
  //then add story to person
  aaron.stories.push(story1);
  aaron.save(callback);
});

答案 2 :(得分:1)

单向或双向关系

您可能会考虑另一种可能性:您是否真的需要双向关联?或者仅将_creator存储在每个Story中就足够了。并且不要为每个list of stories存储Person。仍然可以在搜索中查询故事列表:

let allStoriesOfOneCreator = Stories.find({_creator: person._id});

https://docs.mongodb.com/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/

最后,这取决于您的应用程序要求。您多久需要一次创作者的故事?

答案 3 :(得分:0)

此问题的先前答案很有帮助,但查看更详细的代码可能会很有用。以下代码来自于我的应用程序的Express.js后端。我的应用程序允许用户撰写评论。当查询用户时,我返回用户所做的所有评论。

user_model.js

import mongoose, { Schema } from 'mongoose';


const UserSchema = new Schema({
  firstname: String,
  lastname: String,
  username: { type: String, unique: true },
  reviews: [{ type: Schema.Types.ObjectId, ref: 'Review' }],
}, {
  toJSON: {
    virtuals: true,
  },
});

const UserModel = mongoose.model('User', UserSchema);
export default UserModel;

review_model.js

import mongoose, { Schema } from 'mongoose';

const ReviewSchema = new Schema({
  body: String,
  username: String,
  rating: Number,
}, {
  toJSON: {
    virtuals: true,
  },
});

const ReviewModel = mongoose.model('Review', ReviewSchema);
export default ReviewModel;

review_controller.js

// . . .
export const createReview = (req, res) => {
    const review = new Review();
    review.username = req.body.username;
    review.rating = req.body.rating;
    review.body = req.body.body;
    review.save()
      .then((result) => {
        User.findOne({ username: review.username }, (err, user) => {
            if (user) {
                // The below two line will add the newly saved review's 
                // ObjectID to the the User's reviews array field
                user.reviews.push(review);
                user.save();
                res.json({ message: 'Review created!' });
            }
        });
      })
      .catch((error) => {
        res.status(500).json({ error });
      });
};

user_controller.js

// . . .
// returns the user object associated with the username if any
// with the reviews field containing an array of review objects 
// consisting of the reviews created by the user
export const getUser = (req, res) => {
    User.findOne({ username: req.params.username })
      .populate('reviews')
      .then((result) => {
        res.json(result);
      })
      .catch((error) => {
        res.status(500).json({ error });
      });
  };

答案 4 :(得分:0)

// 如果您是类型脚本用户,则:

import mongoose from 'mongoose';

interface PromotionAttrs {
  price: number;
  startDate: Date;
  endDate: Date;
}

export interface PromotionDoc extends mongoose.Document {
  price: number;
  startDate: string;
  endDate: string;
}

interface PromotionModel extends mongoose.Model<PromotionDoc> {
  build(attrs: PromotionAttrs): PromotionDoc;
}

const promotionSchema = new mongoose.Schema({
  price: {
    type: Number,
  },
  startDate: {
    type: mongoose.Schema.Types.Date,
  },
  endDate: {
    type: mongoose.Schema.Types.Date,
  },
});

promotionSchema.statics.build = (attrs: PromotionAttrs) => {
  return new Promotion(attrs);
};

const Promotion = mongoose.model<PromotionDoc, PromotionModel>(
  'Promotion',
  promotionSchema
);

export { Promotion };
import mongoose from 'mongoose';
import { PromotionDoc } from './promotion';

interface ProductAttrs {
  name: string;
  promotions?: PromotionDoc[];
}

interface ProductModel extends mongoose.Model<ProductDoc> {
  build(attrs: ProductAttrs): any;
}
interface ProductDoc extends mongoose.Document {
  name: string;
  promotions?: PromotionDoc[];
}
const productSchema = new mongoose.Schema({
  promotions: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Promotion',
    },
  ],
});

productSchema.statics.build = (attrs: ProductAttrs) => {
  return new Product(attrs);
};
const Product = mongoose.model<ProductDoc, ProductModel>(
  'Product',
  productSchema
);

export { Product };
const product = await Product.findById(productId);

    if (!product) {
      throw new NotFoundError();
    }
const promotion = Promotion.build({
        price,
        startDate,
        endDate,
      });
      await promotion.save();
      product.promotions?.push();
      await product.save();