为什么我的数组不使用Mongoose填充

时间:2016-06-28 01:14:44

标签: node.js mongodb mongoose mongoose-populate

我有两个架构:设备和地图。

设备:

   var DeviceSchema = mongoose.Schema({
        deviceName:{
            type: String,
            required: true,
            index: true
        },
       roomCapacity: {
            type: Number
        },
        roomImagePath:{
            type: String,
        },
        mapId:{
            type: Schema.Types.ObjectId,
            ref: 'Map',
            required: true
        },
        coords:{
            type: [Number], //[xcoord, ycoord]
            required: true
        },

        createdAt: { type: Date, default: Date.now }
    });

地图

var MapSchema = mongoose.Schema({
    ownerId:{
        type: Schema.Types.ObjectId,
        ref: 'User',
        required: true
    },
    mapName: {
        type: String
    },
    mapImagePath:{
        type: String,
        required: true
    },

    createdAt: { type: Date, default: Date.now },

    devices: [{type: Schema.Types.ObjectId, ref: 'Device'}]
});

如您所见,我的Map有一个引用设备的数组,而我的Device有一个引用地图的mapId字段。现在,我正在尝试调用.populate(),以便我可以检索地图及其数组设备。我在做:

module.exports.getMapByIdAndPopulate = function(mapId, callback){
    Map.findOne({_id: mapId}).populate('devices').exec(callback);
};

这会返回地图,但设备数组不应该是空的。另外,我在我的数据库中创建设备如下:

 var device = new Device({ //create the device
        deviceName: req.body.deviceName,
        roomCapacity: req.body.roomCapacity,
        roomImagePath: roomImagePath,
        mapId: req.body.mapId,
        coords: [req.body.xcoord, req.body.ycoord]
    });

如何使用其设备阵列检索地图?另外,我不知道我是否理解填充正确,但我从不在Map数组中插入任何设备。

2 个答案:

答案 0 :(得分:2)

我已经创建了一个简单的脚本来运行你的模式和查询:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = mongoose.Types.ObjectId;

mongoose.connect("mongodb://localhost/mytestdb");

var db = mongoose.connection;

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {

    // Schemas copied from your code, condensed to reduce clutter
    var DeviceSchema = mongoose.Schema({
        deviceName: {type: String, required: true, index: true},
        roomCapacity: {type: Number},
        roomImagePath: {type: String},
        mapId: {type: Schema.Types.ObjectId, ref: 'Map', required: true},
        coords: {type: [Number], required: true},
        createdAt: {type: Date, default: Date.now}
    });

    // Omitted ownerId for simplicity sake
    var MapSchema = mongoose.Schema({
        mapName: {type: String},
        mapImagePath: {type: String, required: true},
        createdAt: {type: Date, default: Date.now},
        devices: [{type: Schema.Types.ObjectId, ref: 'Device'}]
    });

    var Device = mongoose.model('Device', DeviceSchema);
    var Map = mongoose.model('Map', MapSchema);

    // Add Map
    new Map({
        mapName: "Map 1",
        mapImagePath: "mapImagePath 1",
        createdAt: new Date(),
        devices: []
    }).save().then(function (map1) {

        // Add a Device
        return new Device({
            deviceName: "Device 1",
            roomCapacity: 123,
            roomImagePath: "roomImagePath",
            mapId: map1._id,
            coords: [345, 456]
        }).save().then(function (device1) {

            // Add the new Device back to the map
            map1.devices.push(device1); // Push the whole device, not just the _id, mongoose would handle this for us

            return map1.save();
        })


    }).then(function (saveResult) {
        console.log(saveResult);

        // mapId is now an ObjectId
        var mapId = saveResult._id;

        return Map.findOne({_id: mapId}).populate('devices').exec().then(function (foundMap) {

            console.log(foundMap);

        });

    }).catch(function (err) {
        console.error(err);
    });


});

控制台输出:

首先,console.log包含新保存的Map,其中包含Device的对象ID:

{ __v: 1,
  mapName: 'Map 1',
  mapImagePath: 'mapImagePath 1',
  _id: 5771e0e5739d78441cff5424,
  devices: [ 5771e0e5739d78441cff5425 ],
  createdAt: Tue Jun 28 2016 02:28:53 GMT+0000 }

第二个console.log是已填充的.findOne()

{ _id: 5771e0e5739d78441cff5424,
  mapName: 'Map 1',
  mapImagePath: 'mapImagePath 1',
  __v: 1,
  devices:
   [ { _id: 5771e0e5739d78441cff5425,
       deviceName: 'Device 1',
       roomCapacity: 123,
       roomImagePath: 'roomImagePath',
       mapId: 5771e0e5739d78441cff5424,
       __v: 0,
       createdAt: Tue Jun 28 2016 02:28:53 GMT+0000,
       coords: [Object] } ],
  createdAt: Tue Jun 28 2016 02:28:53 GMT+0000 }

数据库记录显示数据符合预期 - 设备存储了Map的ObjectId,Map将设备的ObjectID存储在"设备"的数组中。路径。

这表明记录已正确填充,这意味着您的架构和查询应该是正确的。

因此,我们应该找出为什么人口并不适合你。

我建议您先检查数据库中的数据,验证"设备" maps集合的数组包含ObjectId但不包含字符串。还要确保正确命名和映射集合(如果不使用默认名称)

以下是我的数据库的测试数据:

maps收藏:

{ 
    "_id" : ObjectId("5771e0e5739d78441cff5424"), 
    "mapName" : "Map 1", 
    "mapImagePath" : "mapImagePath 1", 
    "devices" : [
        ObjectId("5771e0e5739d78441cff5425")
    ], 
    "createdAt" : ISODate("2016-06-28T02:28:53.091+0000"), 
    "__v" : NumberInt(1)
}

devices收藏:

{ 
    "_id" : ObjectId("5771e0e5739d78441cff5425"), 
    "deviceName" : "Device 1", 
    "roomCapacity" : NumberInt(123), 
    "roomImagePath" : "roomImagePath", 
    "mapId" : ObjectId("5771e0e5739d78441cff5424"), 
    "createdAt" : ISODate("2016-06-28T02:28:53.181+0000"), 
    "coords" : [
        NumberInt(345), 
        NumberInt(456)
    ], 
    "__v" : NumberInt(0)
}

答案 1 :(得分:0)

首先,只是为了确保你按照预期的方式进行,当你使用这种语法时

var device = new Device({});

您只是在创建一个对象,所以还没有将它保存到mongo中。为此,只需

var device = new Device({});
device.save(function(err){
    //if err, wrong query
    //else, everything went ok
});

请记住 .save 是异步的。

另一方面,正如您所说,您没有将任何设备的id引用插入到map集合下的devices数组中。我认为你误解了populate方法。 populate方法将查看指定数组中包含的所有id(在本例中),并使用模型中引用的集合填充每个元素。所以,如果你在那个数组中没有任何东西,mongo就没有任何东西可以填充。您必须手动将设备插入地图对象。