mongodb一对n关系中的两种导航

Posted

技术标签:

【中文标题】mongodb一对n关系中的两种导航【英文标题】:two way navigation in a mongo one to n relashionship 【发布时间】:2017-12-13 07:55:55 【问题描述】:

我在猫鼬 relashionship 系统上遇到了困难。 这是我的计划:

const mongoose = require('mongoose');


const RecipeSchema = mongoose.Schema(
  Title:  type: String ,
  Description:  type: String ,
  Complaints: [ type: mongoose.Schema.Types.ObjectId, ref: 'Complaint' ]
); 

const Recipe = mongoose.model('Recipe', RecipeSchema);


const ComplaintSchema = mongoose.Schema(
  Recipe  :  type: mongoose.Schema.Types.ObjectId, ref: 'Recipe' ,
  Message:  type: String 
);

const Complaint = mongoose.model('Complaint', ComplaintSchema);

以下是我保存数据的方式:

var recipeEntity = new Recipe( 
    Title: request.body.Title,
    Description: request.body.Description
);

recipeEntity.save();


var complaintEntity= new Complaint( 
    Message: request.body.Message.trim(),
    Recipe: mongoose.Types.ObjectId(request.body.Message.RecipeId);
);

complaintEntity.save();

到目前为止,一切都很好……至少对我来说是这样!

现在,当我尝试列出带有投诉的食谱时,我得到的只是一个空的投诉数组:

Recipe
    .find()
    .populate('Complaints') 
    .exec(callback);

这是 json 结果:

[
    "Id": "595fe6f89d63700011ee144d",
    "Title": "Chocolate Cake",
    "Description": "aaaa bbb cc d"
    "Complaints": []
]

那么,我在这里缺少什么? 感谢您的支持

【问题讨论】:

【参考方案1】:

好的,我也不得不将记录保存在参考文献中,我采用了这种方法:

RecipeSchema.pre('remove', function(next)  
    Complaint.remove( "Recipe" : this._id ).exec();
    next();
);

ComplaintSchema.pre('remove', function(next) 
    Recipe.findById(this.Recipe).exec((error, item) => 
      var index = item.Complaints.indexOf(item.Complaints.find(e => e._id == this._id));
      item.Complaints.splice(index, 1);
      item.save(() =>  next(); );
    );
);

ComplaintSchema.pre('save', function(next) 
    Recipe.findById(this.Recipe).exec((error, item) => 
      item.Complaints.push(this);
      item.save(() =>  next(); );
    );
);

使用 mongo 架构上可用的此触发器/事件。 效果很好!

【讨论】:

正确的方法。这通常是使用 mongoose 进行删除级联时要走的路。 tks,希望我的回答也有用【参考方案2】:

我将假设您没有在同一次通话中同时保存食谱和投诉。这没有任何意义:每次你提出投诉,你也不会制作食谱。

创建投诉时,您需要保存其关联配方的ObjectId 并且还将投诉的ObjectId 添加/推送到关联配方的投诉中。

如果你关注resource naming conventions,你会得到类似的东西:

// get recipes including complaints
app.get('/recipes', function (req, res) 
    Recipe.find().populate('Complaints').exec(function (err, recipes) 
        console.log(recipes);
    );
);

// add recipe
app.post('/recipes', function (req, res) 
    var recipe = new Recipe(req.body); // simplified
    recipe.save(function (err) 
        if (err)
            return res.send(err);    
        res.send('ok');
    );
);

// add complaint for recipe
app.post('/recipes/:recipeID/complaints', function (req, res) 

    // we query recipe bc we need it after
    Recipe.findById(req.params.recipeID, function (err, recipe) 
        if (err)
            return res.send(err);
        if (!recipe)
            return res.send('No recipe found');

        // add complaint
        var complaint = new Complaint(req.body);
        complaint.Recipe = recipe._id; // add reference in one direction
        complaint.save(function (err) 
            if (err)
                return res.send(err);

            // update recipe
            recipe.Complaints.push(complaint._id); // add reference in other direction
            recipe.save(function (err) 
                if (err)
                    return res.send(err);    
                res.send('ok');
            );
        );
    );

)

我认为这是一本好书:many to many relationship with nosql (mongodb and mongoose)。

【讨论】:

Tks。受到您的解决方案的启发,我在下面开发了该解决方案并在此处发布以帮助遇到类似问题的人。

以上是关于mongodb一对n关系中的两种导航的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB / Mongoose 一对多关系

MongoDB 中的关联查询MongoDB : aggregate/lookup 对比 Mongoose : ref / populate

mongodb第五篇文章~关于mongodb的两种引擎

MongoDB 一对多关系建模

Spring Boot项目中的MongoDB一对多和多对一关系

mongodb用子文档做为查询条件的两种方法