Description
I have the following function designed to update the ObjectIds stored in a given document doc
, at path
, to match those provided in a form submission data
by using atomic push
and pull
functionality.
(ObjectIds are stored in an array like this: schema.add({ myPath: [{type: ObjectId, ref: 'OtherSchema'}] });
function(doc, data, path) {
var storedValue = doc.populated(path),
arr = doc.get(path),
_old = storedValue.map(function(i) { return String(i) }),
_new = _.compact(data[path].split(','));
console.log('Stored Value:');
console.log(storedValue)
console.log('Data at Path:');
console.log(arr);
console.log('Remove:');
console.log(_.difference(_old, _new));
// remove ids
_.difference(_old, _new).forEach(function(val) {
console.log('pulling ' + val);
arr.pull(val);
});
console.log('Add:');
console.log(_.difference(_new, _old));
// add new ids
_.difference(_new, _old).forEach(function(val) {
console.log('pushing ' + val);
arr.push(val);
});
console.log('Updated Value:');
console.log(arr);
}
If the doc
has already had path
populated, two unexpected behaviours occur:
- ObjectIds aren't removed
- ObjectIds that are added exist in a half-populated state
Console.log
output demonstrating both in the above function:
Stored:
[ 51f9fe338507730000000004 ]
Item Data:
[ { name: 'Jimmy',
_id: 51f9fe338507730000000004 } ]
Remove:
[ '51f9fe338507730000000004' ]
pulling 51f9fe338507730000000004
Add:
[ '51f9fe338507730000000007' ]
pushing 51f9fe338507730000000007
Updated:
[ { name: 'Jimmy',
_id: 51f9fe338507730000000004 }, { _id: 51f9fe338507730000000007 } ]
re: 1, this seems like a bug. The documentation here implies that you should be able to remove ids from an array, although it doesn't mention what happens if the array has been populated.
re: 2, as you can see the newly added object looks populated (is an object) but hasn't been loaded from the database yet (so has no name property). What's the best way to handle this? Repopulate the path after saving the document?
It might be best in my particular case to specifically detect that the path being updated has been populated, unpopulate it, make the atomic changes to the array, then repopulate the path after the document has been saved. There doesn't seem to be any api to unpopulate a path, and I don't want to blindly do this:
document.set(path, document.populated(path));
... because I think that would cause the document to think that the entire value of path
has been modified.
Any hints on how to best make all this work would be great, Cheers.