4

I use lodash find to query object from array, then I set the property of that object but when I print out the array after setting this property, it is unchanged.

I would be grateful for some comments from someone more experienced on handling objects with lodash in JavaScript. Feel also free to comment on the way I formulate the problem or to edit the content to make it more easily searchable for other people via search engines.

Isolated code:

console.log('socket.io', token);
console.log(realtime);
let session = yield _.find(realtime, function(data) {
    return data.token === token;
});
console.log('session object to be set');
console.log(session);
if (!session.socket) {
    console.log('setting session for '+session.token+' socket '+socket.id);
    session.socket = socket.id;
    console.log('local reference after set');
    console.log(session);
    console.log('realtime after set');
    console.log(realtime);
}

Result, this is the output from console.log:

socket.io 268fc477-d4ee-4ed4-88cd-648539397df2
[ { token: '268fc477-d4ee-4ed4-88cd-648539397df2' } ]
session object to be set
{ token: '268fc477-d4ee-4ed4-88cd-648539397df2' }
setting session for 268fc477-d4ee-4ed4-88cd-648539397df2 socket /#iEqqcIsBbATDs1a-AAAB
local reference after set
{ token: '268fc477-d4ee-4ed4-88cd-648539397df2',
socket: '/#iEqqcIsBbATDs1a-AAAB' }
realtime after set
[ { token: '268fc477-d4ee-4ed4-88cd-648539397df2' } ]

Expected result, look at the last print, I want this object to be modified in the data structure that object originated from:

socket.io 268fc477-d4ee-4ed4-88cd-648539397df2
[ { token: '268fc477-d4ee-4ed4-88cd-648539397df2' } ]
session object to be set
{ token: '268fc477-d4ee-4ed4-88cd-648539397df2' }
setting session for 268fc477-d4ee-4ed4-88cd-648539397df2 socket /#iEqqcIsBbATDs1a-AAAB
local reference after set
{ token: '268fc477-d4ee-4ed4-88cd-648539397df2',
socket: '/#iEqqcIsBbATDs1a-AAAB' }
realtime after set
[ {
token: '268fc477-d4ee-4ed4-88cd-648539397df2',
socket: '/#iEqqcIsBbATDs1a-AAAB'
} ]

Public gist, feel free to also comment here. I hope this question will be also useful for others.

Edit Lodash reference says Returns the matched element, else undefined. I am not sure if that means that it returns cloned object or reference to queried object.

Marek
  • 1,413
  • 2
  • 20
  • 36
  • Do you need to call `.value()`? A bunch of stuff is lazily evaluated and won't resolve until you do. – Casey Mar 19 '16 at 03:42
  • Please detail more, `.value()` on which object, use it for setting value to property? – Marek Mar 19 '16 at 03:43
  • I mean that to get the result I think you need to call `session.value()`. – Casey Mar 19 '16 at 03:44
  • You mean to handle (resolve) the `promise`? Result is resolved because of `yield` keyword, I `use strict` the environment and code is inside a promise. – Marek Mar 19 '16 at 03:48
  • Oh. Well that's what I get for not reading closely. Sorry, carry on. – Casey Mar 19 '16 at 03:48
  • My bad, I should have include the `co` that the code is nested in, just didn't wanted to make it too confusing, in the output we can see the value as resolved so I though it is better to skip that part. – Marek Mar 19 '16 at 03:51
  • Could you include the function the code is nested in? – gnerkus Mar 19 '16 at 04:52
  • The problem is not with `_.find` which will indeed return the found element. I suggest you try `let session = yield Promise.resolve(_.find(realtime, function(data) { return data.token === token; }));`. –  Mar 19 '16 at 06:53

1 Answers1

3

What is happening is that the value you are yielding is an object, which according to co documentation will treat each value in the object as a promise to be resolved, and will return a (new) object with the same keys and values being the values of the resolved promises.

In your case, since the values of the properties (such as token) are not promises, the values are passed through as is, so the object which is returned looks like the one you yielded, but actually it's a new object, not the one inside realtime. The code inside co which is creating this new object is here:

if (isObject(obj)) return objectToPromise.call(this, obj);

To prevent this from happening, you need to do

let session = yield Promise.resolve(_.find(realtime, data => data.token === token));

If you had yielded a single scalar value, co would have complained that this was not a yieldable. However, since you yielded an object value, co interpreted it as an object-type yieldable. Which raises the issue--why are you trying to yield a non-yieldable in the first place?

As a final note:

Lodash reference says Returns the matched element, else undefined. I am not sure if that means that it returns cloned object or reference to queried object.

Of course, _.find returns the found element itself, not a clone of it.

  • Just tested, works like a charm. Thank you very much, not only for solution but also for clear explanation, cheers! – Marek Mar 19 '16 at 07:45