如何在子文档中填充模型实例数组? MongoDB猫鼬

Posted

技术标签:

【中文标题】如何在子文档中填充模型实例数组? MongoDB猫鼬【英文标题】:How to populate an array of model instances inside a subdocument? MongoDB Mongoose 【发布时间】:2020-04-29 08:53:32 【问题描述】:

我有一个嵌套为数组的子文档。在该子文档中,我引用了其他模型。使用.Find.Populate 方法,我可以接收子文档中引用的单个模型的整个对象(查看下面的停止),但不能接收模型实例数组,事实/建议。对于事实/建议,我收到一组对象_ids。我可能只需要那些_ids 并进行另一个查询,但这似乎很混乱。

有没有办法填充数组?我需要使用 Aggregate + $lookup 吗?是否有更多的 Mongo 方法来重组 Schema 以简化这一点?

感谢大家的帮助!

我的名为 TourStop 的子文档:

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const TourStopSchema = new Schema(
    stop: 
        type: Schema.Types.ObjectId,
        ref: 'Stop',
        required:[true, 'must have a Stop'],
    ,
    mandatory: 
        type:Boolean,
        default: false
    ,
    check_in_time: 
        type: Number,
        default: 0
    ,
    order: 
        type:Number,
        required: [true, 'Must have an order']
    ,
    facts: [
        type: Schema.Types.ObjectId,
        ref: 'Fact'
    ],
    recommendations: [
        type: Schema.Types.ObjectId,
        ref: 'Recommendation'
    ]
);


module.exports = TourStopSchema;

TourStops 位于 Tour 内部:

const mongoose = require('mongoose');
const TourStopSchema = require('../subdocs/tour_stop');
const Schema = mongoose.Schema;

const tourSchema = new Schema(
    name: 
        type:String,
        required:[true,'Name is required!'],
        unique: true
    ,
    city: 
        type: String,
        required: [true, 'City is required!']
    ,
    tourStops:[TourStopSchema]
);

const Tour = mongoose.model('Tour', tourSchema);
module.exports = Tour;

Stop 模式填充得很好。

const mongoose = require('mongoose');
const LocationSchema = require('../subdocs/location');
const ImageSchema = require('../subdocs/image');
const Schema = mongoose.Schema;

const stopSchema = new Schema(
    name:
        type: String,
        required:[true,'Must have a name!']
    ,
    location:LocationSchema,
    categories: 
        type: [String],
        default:[]
    ,
    images:
        type:[ImageSchema],
        default:[]
    
);

const Stop = mongoose.model('Stop', stopSchema);
module.exports = Stop; 

而未正确填充的 Fact Schema 则返回带有 _ids 的字符串数组

事实:

const mongoose = require('mongoose');
const ImageSchema = require('../subdocs/image');
const Schema = mongoose.Schema;

const factSchema = new Schema(
    stop: 
        type: Schema.Types.ObjectId,
        ref:'Stop',
        required:[true, 'A Fact must have a Stop!'],
    ,
    description: 
        type: String,
        required: [true,'A Fact must have a description!']
    ,
    images: 
        type:[ImageSchema],
        default:[]
    
);

const Fact = mongoose.model('Fact', factSchema);
module.exports = Fact;

我正在运行测试以检查架构是否正确连接以检索 TourStop 的所有属性:

it('saves a full relation graph', (done) => 
    User.findOne( first_name: 'Dean' )
        .populate(
            // in that user find the tours property and load up all tours
            path: 'tours',
            // inside of all those tours, find the tourstops property and load all associated stops
            populate: 
                path: 'tour_stops.facts',
                model: 'Fact'
            ,
            populate: 
                path: 'tour_stops.stop',
                model: 'Stop'
            
        )
        // .populate('tours.tour_stops[0].facts')
        .then((user) => 
            // console.log(user.tours[0].tour_stops[0].stop);
            console.log(user.tours[0].tour_stops[0]);
            // console.log(Array.isArray(user.tours[0].tour_stops[0].facts))
            assert(user.first_name === 'Dean' );
            assert(user.tours.length === 1);
            assert(user.tours[0].name === "Awesome New Tour");
            assert(user.tours[0].tour_stops[0].stop.name === 'Jaffa Clock Tower');
            // assert(user.tours[0])
            // assert(user.blogPosts[0].title === 'JS is Great');
            // assert(user.blogPosts[0].comments[0].content === 'Congrats on great post!' );
            // assert(user.blogPosts[0].comments[0].user.name === 'Joe' )
            done();
        )
    )

【问题讨论】:

您有 5-6 个架构,但您只显示一个架构代码。我们怎么能这样理解模式之间的关系呢? 我将更新以包含其他相关架构!感谢您的帮助。 旅游模式怎么样? TourStop 作为子文档嵌套在 Tour 中,我添加了 Tour 架构来反映。 【参考方案1】:

您可以使用以下代码填充游览、停靠点、事实和建议。 注意在model 属性中,我们不应该给出字符串值,而是模型本身。所以你需要将它们导入到你的代码中。

  User.findOne( first_name: "Dean" )
    .populate(
      path: "tours",
      populate: 
        path: "tourStops.stop",
        model: Stop
      
    )
    .populate(
      path: "tours",
      populate: 
        path: "tourStops.facts",
        model: Fact
      
    )
    .populate(
      path: "tours",
      populate: 
        path: "tourStops.recommendations",
        model: Recommendation
      
    )
    .then(user => 
       console.log(user);
    );

【讨论】:

谢谢@SuleymanSah!这是有效的!在这种特定情况下,它似乎可以完成这项工作,我只是在对关联进行测试。但是,您认为通过 .Aggregate 和 $lookup 尝试这样做会更好吗?对数据库进行 3 次单独的 .Populate 调用似乎很繁重。对此有何看法?? @ruskibenya 另一种选择是使用嵌套查找,如here 所述。由于您使用了填充,所以我回答了填充,您可以考虑接受这个作为答案吗?

以上是关于如何在子文档中填充模型实例数组? MongoDB猫鼬的主要内容,如果未能解决你的问题,请参考以下文章

在子文档 MongoDB 中检索数组

在子文档 MongoDB 中检索数组

如何使用猫鼬“填充”来指定不同集合的现有文档的路径?

如何填充一组子`ref`ed文档猫鼬?

mongodb在子文档数组的数组中获取不同的项目

EJS:如何在 EJS 文件中呈现来自猫鼬的两个或多个填充集合