JSON stringify in Node JS not serializing array of objects

寵の児 提交于 2019-12-02 01:28:58

问题


I am using sails.js (node js framework).

I am trying to JSON.stringify one of the objects, but when I do that it omits one of the fields (rooms array below).

Here is what console.log(object) gives me:

[ { rooms: [ [Object], [Object] ],
    state: '53df76c278999310248072c6',
    name: 'Sydney Center',
    menuItems: null,
    createdAt: Mon Aug 04 2014 23:42:08 GMT+0300 (Jerusalem Summer Time),
    updatedAt: Mon Aug 04 2014 23:42:08 GMT+0300 (Jerusalem Summer Time),
    id: '53dff0205c89c03428a31cee' },
  { rooms: [ [Object], [Object], [Object] ],
    state: '53df76c278999310248072c6',
    createdAt: Mon Aug 04 2014 23:43:21 GMT+0300 (Jerusalem Summer Time),
    menuItems: null,
    name: 'Batata Center',
    updatedAt: Mon Aug 04 2014 23:51:11 GMT+0300 (Jerusalem Summer Time),
    id: '53dff06a5c89c03428a31cf3' } ]

JSON output (rooms are not printed):

    [
      {
        "state": "53df76c278999310248072c6",
        "name": "Sydney Center",
        "menuItems": null,
        "createdAt": "2014-08-04T20:42:08.885Z",
        "updatedAt": "2014-08-04T20:42:08.885Z",
        "id": "53dff0205c89c03428a31cee"
      },
      {
        "state": "53df76c278999310248072c6",
        "createdAt": "2014-08-04T20:43:21.999Z",
        "menuItems": null,
        "name": "Batata Center",
        "updatedAt": "2014-08-04T20:51:11.740Z",
        "id": "53dff06a5c89c03428a31cf3"
      }
    ]

What might be the problem? The rooms data seems to be fine.

For the complete function (SailsJS):

getCentersData: function(req, res) {

    sails.log.info('Teacher.getCentersData: ', req.user.id);
    var userId = req.user.id;

    async.auto({

        teacher: function(cb) {
            Teacher.findOne({ user: userId }).populate('centers').exec(cb);
        },

        centers: [
            'teacher', function(cb, results) {
                var allCentersIds = _.pluck(results.teacher.centers, 'id');
                Center.findById(allCentersIds).populate('rooms').exec(cb);
            }
        ],

        rooms: [
            'centers', function(cb, results) {
                var allRoomIds = [];
                _.each(results.centers, function(center) {
                    allRoomIds = _.union(allRoomIds, _.pluck(center.rooms, 'id'));
                });
                Room.findById(allRoomIds).populate('children').exec(cb);
            }
        ],

        children: [
            'rooms', function(cb, results) {
                var allChildrenIds = [];
                _.each(results.rooms, function (room) {
                    allChildrenIds = _.union(allChildrenIds, _.pluck(room.children, 'id'));
                });
                Child.findById(allChildrenIds).populate('parents').exec(cb);
            }
        ],

        parentUsers: ['children', function(cb, results) {
            var allParentIds = [];
            _.each(results.children, function (child) {
                allParentIds = _.union(allParentIds, _.pluck(child.parents, 'id'));
            });
            Parent.findById(allParentIds).populate('user').exec(cb);
        }],

        map: ['parentUsers', function (cb, results) {

            // map children to parents
            var parentsMapper = _.indexBy(results.parentUsers, 'id');
            var childrenMappedToParents = _.map(results.children, function (child) {
                var _child = child.toObject();
                _child.parents = _.map(child.parents, function (parent) {
                    return parentsMapper[parent.id];
                });
                return _child;
            });
            var childrenMapper = _.indexBy(childrenMappedToParents, 'id');

            // map rooms to children
            var roomsMappedToChildren = _.map(results.rooms, function (room) {
                var _room = room.toObject();
                _room.children = _.map(room.children, function (child) {
                    return childrenMapper[child.id];
                });
                return _room;
            });
            var roomsMapper = _.indexBy(roomsMappedToChildren, 'id');

            // map center to rooms
            var centersMappedToRooms = _.map(results.centers, function (center) {
                var _center = center.toObject();
                _center.rooms = _.map(center.rooms, function (room) {
                    return roomsMapper[room.id];
                });
                return _center;
            });

            sails.log.info('centersMappedToRooms',centersMappedToRooms ); // includes rooms array
            sails.log.info('centersMappedToRooms json: ', JSON.stringify(centersMappedToRooms)); // does not include rooms array

            return cb(null, centersMappedToRooms);

        }]
    }, function(err, results) {
        if (err) {
            return res.serverError(err);
        }

        // added prints
        sails.log.info("results.map: ", results.map); 
        sails.log.info("JSON.stringify(results.map): ", JSON.stringify(results.map)); // same same, does not print the rooms array

        return res.json(results.map);
    });

},

EDITED

Schema:

schema: true,

attributes: {

    name: {
        type: 'string',
        required: true,
        minLength: 5
    },

    // Many-To-Many association with Teacher model
    teachers: {
        collection: 'teacher',
        via: 'centers'
    },

    // One-To-Many association with State model
    state: {
        model: 'state'
    },

    // One-To-Many association with Room model
    rooms: {
        collection: 'room',
        via: 'center'
    },

    // One-To-One association with Principal model
    principal: {
        model: 'principal'
    },

    menuItems: {
        type: 'array',
        defaultsTo: null
    }
},

回答1:


Because Waterline queries return models, not plain javascript objects, they have additional properties and functions on them. One of these is an overridden toJSON() function which removes attributes that have not been populated. What seems to be happening here is that you are attaching objects to a parent model which doesn't know it has children that have been populated so it strips off the values.

The reasoning behind this is so that if you query for all Users and don't populate Rooms you don't get an incorrect result showing an empty rooms array.

I'm not sure what all you are manipulating here but the reason it works if you _.cloneDeep is because it removes the custom toJSON field. This is the recommend strategy when you are mutating a parent object from a query like this.



来源:https://stackoverflow.com/questions/25142731/json-stringify-in-node-js-not-serializing-array-of-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!