0

What I am trying to do I am trying to deeply re-map an existing array of objects using a mapping function. The mapping it self works as you can see in "output 1" below, but the deep assignment of the object is not working, which means, it is not taking place (see "output 2").

(Background) less important info: (Due to the 'deep population' constraint in waterline (sailsJS), i am trying to do the population manually using async's auto)

code:

    var roomsMapper = _.indexBy(results.rooms, 'id'); // maps id to a new room object that has array of children
    _.each(data.centers, function (center, index) {
        var mappedRooms = _.map(center.rooms, function (room) {
            return roomsMapper[room.id];
        });

        sails.log.info("mappedRooms: ", mappedRooms); // as expected see output 1
        data.centers[index].rooms = mappedRooms;
        sails.log.info("data.centers[index]: ", data.centers[index]); // not as expected, see output 2
    });

    sails.log.info("data.centers: ", data.centers); // new values are not assigned

output1 (the mapped value has array of children):

info: mappedRooms:  [ { children:
     [ { name: 'Child Khoury',
         birthday: Sun Dec 28 2008 00:00:00 GMT+0200 (Jerusalem Standard Time),
         sex: 'M',
         allergies: null,
         id: '53dff26a3e5cb1b01f2f2e13',
         createdAt: Mon Aug 04 2014 23:51:54 GMT+0300 (Jerusalem Summer Time),
         updatedAt: Mon Aug 04 2014 23:51:54 GMT+0300 (Jerusalem Summer Time),
         room: '53dff0205c89c03428a31cf0' },
       { name: 'Ashqar Sameeh',
         birthday: Tue Feb 01 2000 00:00:00 GMT+0200 (Jerusalem Standard Time),
         sex: 'F',
         allergies: null,
         id: '53dff2803e5cb1b01f2f2e14',
         createdAt: Mon Aug 04 2014 23:52:16 GMT+0300 (Jerusalem Summer Time),
         updatedAt: Mon Aug 04 2014 23:52:16 GMT+0300 (Jerusalem Summer Time),
         room: '53dff0205c89c03428a31cf0' } ],
    center: '53dff0205c89c03428a31cee',
    name: 'sydney room2',
    min_age: 5,
    max_age: 7,
    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: '53dff0205c89c03428a31cf0' },
  { children:
     [ { name: 'Samih Samama',
         birthday: Mon Dec 29 2008 00:00:00 GMT+0200 (Jerusalem Standard Time),
         sex: 'M',
         allergies: [Object],
         id: '53dff29e3e5cb1b01f2f2e16',
         createdAt: Mon Aug 04 2014 23:52:46 GMT+0300 (Jerusalem Summer Time),
         updatedAt: Mon Aug 04 2014 23:52:46 GMT+0300 (Jerusalem Summer Time),
         room: '53dff0205c89c03428a31cef' } ],
    center: '53dff0205c89c03428a31cee',
    name: 'sydney room1',
    min_age: 0,
    max_age: 3,
    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: '53dff0205c89c03428a31cef' } ]

output2 (mappedRooms is not assigned- children array is missing):

    info: data.centers[index]:  { rooms:
       [ { name: 'sydney room2',
           center: '53dff0205c89c03428a31cee',
           min_age: 5,
           max_age: 7,
           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: '53dff0205c89c03428a31cf0' },
         { name: 'sydney room1',
           center: '53dff0205c89c03428a31cee',
           min_age: 0,
           max_age: 3,
           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: '53dff0205c89c03428a31cef' } ],
      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' }
Travis Webb
  • 14,688
  • 7
  • 55
  • 109
user2867106
  • 1,139
  • 1
  • 13
  • 31

2 Answers2

1

Object assignment is by reference, not by value. I use the following to copy one object into another:

function extendObject(destination, source) {
  for (var property in source) {
    if (source[property] && source[property].constructor &&
     source[property].constructor === Object) {
      destination[property] = destination[property] || {};
      arguments.callee(destination[property], source[property]);
    } else {
      destination[property] = source[property];
    }
  }
  return destination;
};

So, as an example:

var obj1 = { a: { foo: 'bar' } };
var obj2 = { b: { bar: 'foo' } };
extendObject(obj2, obj1);
obj1.a.foo = "different";
console.log(obj1);
console.log(obj2);

Would output:

{ a: { foo: 'different' } }
{ b: { bar: 'foo' }, a: { foo: 'bar' } }

[Edit] - If I'm understanding the problem correctly, this would essentially do the same thing:

var roomsMapper = _.indexBy(results.rooms, 'id');
_.each(data.centers, function (center, index) {
  var mappedRooms = [];
  for( i in center.rooms ) {
    mappedRooms.push(roomsMapper[center.rooms[i].id]);
  }
  data.centers[index].rooms = mappedRooms;
});
FunnyLookinHat
  • 569
  • 1
  • 6
  • 13
  • I know it is copied by reference, but what I don't get is: why when I change the reference of center.rooms to point to a new object (mappedRooms) and then print the center I see that center.rooms is still pointing to the old reference? – user2867106 Aug 05 '14 at 12:47
  • No idea - but I have a feeling it has to do with data.centers not being what you think it is ( i.e. that's iterating as well ). I'll edit my answer for a suggestion that I _think_ understands your data type. Also - _.each is asynchronous - so it could be that you want _.eachSeries() – FunnyLookinHat Aug 05 '14 at 13:41
1

I tried it, could not really get it why when you pass center to the map callback function and modify one of its properties somehow the reference is lost.

Anyway, the following worked for me:

    var roomsMapper = _.indexBy(results.rooms, 'id'); 
    var mappedCenters = _.map(data.centers, function (center) {
        var _center = center.toObject(); // create new object
        _center.rooms = _.map(center.rooms, function (room) {
            return roomsMapper[room.id];
        });
        return _center;
    });
  • it worked for me, thanks. but I will not mark it as solved because I don't understand too, maybe someone will answer. – user2867106 Aug 05 '14 at 15:49