簡體   English   中英

具有一對多關系的 Mongoose 文檔引用

[英]Mongoose document references with a one-to-many relationship

我正在為一個新項目設計數據庫結構,我對 MongoDB 很陌生,顯然是 Mongoose。

我讀過 Mongooses population文檔,它有一個一對多的關系,一個Person文檔到許多Story文檔,但讓我感到困惑的部分是Story文檔不是引用它所屬的Person文檔, Person schema 有它的設置,因此它有一系列它“擁有”的Story文檔。

我正在設置與此非常相似的東西。 但我一直認為在創建新的Story文檔時使用Person文檔 ID 會更容易。 但也許那只是因為我更熟悉使用連接的 MySQL 關系。

如果這是最好的方法(我確信它是,因為它在文檔中),當創建新的Story文檔時,更新它所屬的關聯People文檔中的故事數組的最佳方法是什么? 我看了但找不到任何更新現有文檔以添加對其他文檔的引用(或為此刪除它們)的示例

我確定這是一個我剛剛忽略的簡單解決方案,但任何幫助都會很棒。 謝謝!

參考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);
});

我相信這就是您要找的。 或者,您可以改用嵌套集合

之前對這個問題的回答很有幫助,但看到更詳細的代碼可能會有用。 下面的代碼來自我的應用程序的 Express.js 后端。 我的應用程序允許用戶撰寫評論。 當查詢用戶時,我返回用戶所做的所有評論。

用戶模型.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 lines 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 });
      });
};

用戶控制器.js

 export const createUser = (req, res) => {
   const user = new User();
   user.username = req.body.username;
   user.email = req.body.email;
   user.save()
       .then((result) => {
            res.json({ message: 'User created!', result });
        })
        .catch((error) => {
          res.status(500).json({ error });
        });
    };

// . . .
// 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 });
      });
  };

正如人口文件所說

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);
});

單向或雙向關系

您可能會考慮另一種可能性:您真的需要雙向關聯嗎? 或者僅將_creator存儲在每個Story中就足夠了嗎? 並且不要存儲每個Person list of stories 仍然可以在搜索中查詢故事列表:

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

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

最后,這取決於您的應用程序的要求。 您多久需要一次創作者的故事?

這是創建一對多關系的好方法。

  1. 首先,我們在 Comment.js 中定義 Comment 模型。
const mongoose = require("mongoose");

const Comment = mongoose.model(
  "Comment",
  new mongoose.Schema({
    username: String,
    text: String,
    createdAt: Date
  })
);

module.exports = Comment;
  1. 在 Tutorial.js 中,像這樣添加評論數組:


const mongoose = require("mongoose");

const Tutorial = mongoose.model(
  "Tutorial",
  new mongoose.Schema({
    title: String,
    author: String,
    images: [],
    comments: [
      {
        type: mongoose.Schema.Types.ObjectId,
        ref: "Comment"
      }
    ]
  })
);

module.exports = Tutorial;
  1. 在 server.js 中,添加 createComment 函數。

const createComment = function(tutorialId, comment) {
  return db.Comment.create(comment).then(docComment => {
    console.log("\n>> Created Comment:\n", docComment);

    return db.Tutorial.findByIdAndUpdate(
      tutorialId,
      { $push: { comments: docComment._id } },
      { new: true, useFindAndModify: false }
    );
  });
};

// 如果你是類型腳本用戶那么:

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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM