_.merge 克隆子文档而不是更新

_.merge clones sub-documents instead of updating

在我的 Angular fullstack 项目中,我尝试更新一个项目,向其添加一个新的子文档。在合并之前检查我的 req.body 时,一切看起来都应该如此。然而,在合并更新后的文档后,它应该添加了一个新的子文档,唯一的问题是这个新文档是一个已经存在的文档的克隆,而不是它应该是的那个。

_.merge 来自 lodash

代码:

    console.log('');
    console.log('notes before merging : ', entry.notes);

    console.log('');
    console.log('body.notes before merging : ', req.body.notes);

    var updated = _.merge(entry, req.body);

    console.log('');
    console.log('notes after merging : ', updated.notes); 


当 运行 代码时我的控制台结果:

notes before merging :  
[
    { 
        content: '<p>testing</p>',
        date: Thu Apr 16 2015 10:14:44 GMT+0200 (Rom, sommertid),
        writer: 55193679026666b00554d00e,
        _id: 552f6f7435828478156f6103,
        notes: [] 
    }
]

body.notes before merging :  
[ 
    { 
        content: '<p>testing</p>',
        date: Thu Apr 16 2015 10:14:44 GMT+0200 (Rom, sommertid),
        writer: 55193679026666b00554d00e,
        _id: 552f6f7435828478156f6103,
        notes: [] 
    },
    { 
        content: '<p>bla bla</p>',
        date: '2015-04-16T08:25:24.431Z',
        writer: 55193679026666b00554d00e
    }
]

notes after merging :  
[
    { 
        content: '<p>testing</p>',
        date: Thu Apr 16 2015 10:14:44 GMT+0200 (Rom, sommertid),
        writer: 55193679026666b00554d00e,
        _id: 552f6f7435828478156f6103,
        notes: [] 
    },
    { 
        content: '<p>testing</p>',
        date: Thu Apr 16 2015 10:14:44 GMT+0200 (Rom, sommertid),
        writer: 55193679026666b00554d00e,
        _id: 552f6f7435828478156f6103,
        notes: [] 
    }
]

尝试使用 _.extend_.assign 代替:

var updated = _.assign(entry, req.body);

ShitalShah 的 answer 强调了合并和扩展之间的差异,这些差异导致合并后的结果对象出现重复,但本质上:

Here's how extend/assign works: For each property in source, copy its value as-is to destination. if property values themselves are objects, there is no recursive traversal of their properties. Entire object would be taken from source and set in to destination.

Here's how merge works: For each property in source, check if that property is object itself. If it is then go down recursively and try to map child object properties from source to destination. So essentially we merge object hierarchy from source to destination. While for extend/assign, it's simple one level copy of properties from source to destination.

JSBin来说明区别:

var dest = {
  p: { x: 10, y: 20},
};

var src = {
  p: { x: 20, z: 30},
};

console.log(_.merge(dest, src)); 
/*
[object Object] {
  p: [object Object] {
    x: 20,
    y: 20,
    z: 30
  }
}
*/

console.log(_.extend(dest, src));
/*
[object Object] {
  p: [object Object] {
    x: 20,
    z: 30
  }
}
*/