What is the reason behind fullstack-angular generator utilizing Lo-Dash's merge rather than document.set?

This is the original code snippet used for updating:

exports.update = function(req, res) {
  if(req.body._id) { delete req.body._id; }
  Thing.findById(req.params.id, function (err, thing) {
    if (err) { return handleError(res, err); }
    if(!thing) { return res.send(404); }
    var updated = _.merge(thing, req.body);
    updated.save(function (err) {
      if (err) { return handleError(res, err); }
      return res.json(200, thing);
    });
  });
};

Note particularly the line of code that reads:

var updated = _.merge(thing, req.body);
. This line works well with Schema properties that are primitives but fails when dealing with a schema property that is an array.

The main issue stems from the fact that thing is a mongoose document, whereas req.body is a javascript object.

I have formulated two hypotheses to pinpoint the core problem:

  1. _.merge() mandates the first argument to be an object, leading to conflicts when passed a document.
  2. _.merge() only successfully merges objects with equivalent keys and types. Due to one being a document and the other an object, a mismatch arises.

An illustration can be seen in this example where name updates accurately but arr does not. The update operation works seamlessly on both properties when thing.set(req.body) is utilized instead of

var updated = _.merge(thing, req.body).

thing.html

<div class="container">
  <form ng-submit="update()">
    <div class="form-group">
      <label>Name</label>
      <input class="form-control" ng-model="thing.name">
    </div>
    <div class="form-group">
      <label>Arr</label>
      <input
        type="text"
        class="form-control"
        ng-repeat="el in thing.arr"
        ng-model="thing.arr[$index]">
    </div>
    <button 
      class="btn btn-default"
      type="submit">
      Update
    </button>
  </form>

  {{thing | json}}
</div>

thing.controller.js (front end)

.controller('MainCtrl', function ($scope, $http) {
  $http.get('/api/things')
    .success(function(things) {
      $scope.thing = things[0];
    });
  $scope.update = function() {
    $http.put('/api/things/' + $scope.thing._id, $scope.thing)
      .success(function(newThing) {
        console.log('updated thing: ', newThing);
      })
      .error(function() {
        console.log('unable to update thing');
      });
  };
});

thing.model.js

'use strict';

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var ThingSchema = new Schema({
  name: String,
  arr: []
});

module.exports = mongoose.model('Thing', ThingSchema);

thing.controller.js (backend)

'use strict';

var _ = require('lodash');
var Thing = require('./thing.model');

exports.update = function(req, res) {
  if(req.body._id) { delete req.body._id; }
  Thing.findById(req.params.id, function (err, thing) {
    if (err) { return handleError(res, err); }
    if(!thing) { return res.send(404); }
    var updated = _.merge(thing, req.body);
    updated.save(function (err) {
      if (err) { return handleError(res, err); }
      return res.json(200, thing);
    });
  });
};

function handleError(res, err) {
  return res.send(500, err);
}

These questions remain:

  1. What limitations arise from using _.merge()?
  2. Why did the developers of the angular-fullstack generator opt for _.merge()? Their choice likely hinges on a specific rationale given their knowledge of its behavior.

Answer №1

Even after trying what was recommended in a previous answer, calling 'markModified' on the _.merge return value did not solve the issue at hand. The problem identified by Adam Zerner is that using _merge results in the 'updated' object containing incorrect data for array properties. I have encountered this same issue while using the angular-fullstack generator. For instance, when I remove elements from an array, this modification does not get saved in Mongoose/mongo. However, if I utilize the set function on the mongoose document (as suggested by Zerner), the problem is resolved for me. I came across a discussion thread related to this topic: Here. It proposes replacing _merge with _extend (refer to this link), which also proved effective in solving the issue for me.

Answer №2

Make sure to use the method "markModified" with the user's information. http://mongoosejs.com/docs/api.html#document_Document-markModified

var updated = _.merge(store, req.body);
updated.markModified('foo_name');
updated.save(function (err) {
  if (err) {
    return handleError(res, err);
  }
  return res.json(200, store);
});

Answer №3

After updating from Lodash 3.10.1 to the latest version 4.6.1, I finally got _.merge to work properly. I had been struggling with this issue for some time, and even switching to _.assign in generator-angular-fullstack (version 3.3.0) didn't solve the problem as it did before. The new version of Lodash, v4.6.1, seems to have resolved this issue for me. Despite seeing many npm modules still using v3.10.1 of Lodash as a dependency, so far I haven't encountered any compatibility issues.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sending information into MySQL using NodeJS with the help of Postman

As a newcomer in the field, I am exploring how to combine MySQL with nodeJS for integrating projects into WordPress. app.post('/users/add', (req, res) => { id = req.body.id, firstname = req.body.firstname, surname = req.body.surname ...

Try enabling automatic status bar filling in Onsen UI when working with AngularJS

Completely new to AngularJS, I am trying to understand how to use ons.enableAutoStatusBarFill(); in order to prevent my menus from overlapping the status bar. This is how I have set up my controller: var mod = ons.bootstrap('app', ['onsen& ...

Display or conceal elements using the unique identifier selected from a dropdown menu in JavaScript

I have been searching the internet for a solution to my issue but nothing seems to be working. Here is the problem: Unfortunately, I cannot modify the TR TD structure and am unable to use DIVs. I am trying to dynamically display certain TD elements based ...

How can I send dynamic props between pages using Next.js?

I am currently exploring Next.js and attempting to create a page (index.js) that fetches data about different countries and then displays this information. I would like each country element displayed on the page to have a button that leads to another page ...

Next.js encounters an error when importing web3

Currently, I am utilizing next js and material ui to create a demo dapp for educational purposes. With metamask installed, I have successfully implemented a "connect to wallet" button. My issue arises when attempting to import the Web3 constructor. This i ...

What is the proper procedure for configuring Babel and executing "npm run dev" in the terminal without encountering the "ERROR in ./src/js/index.js" message?

My goal is to include the babel/polyfill with the index.js files using webpack. After completing the setup, I tried running "npm run dev" in the command prompt but encountered an error. The initial line of the error message said "ERROR in ./src/js/index.js ...

Sharing data between child and parent components, and then passing it on to another child component in React Js

I have a scenario where I am passing props from a child component B to parent component A, and then from parent component A to child component C. Everything works fine when I pass the data from component B to A, but I encounter an issue when I try to set a ...

Is there a way to retrieve the current object as a JSON string from inside the object using either jquery or javascript?

Looking for a way to return the current instance as a JSON text so that the values can be sent via an ajax request to a server-side script. Uncertain about where to apply the "this" keyword in a jQuery selector function Actor(){ this.input=function(pnam ...

Displaying a momentjs object within Angular templates

Looking to display a momentjs object, not an ISO8601 string, in AngularJS templates. For example: $scope.time = moment(); When I try the following in my template: <span ng-bind="time"></span> or <span>{{time}}</span> I want to ...

Filter the array while maintaining its current structure

I'm struggling to create an array filter that can handle exact and partial data within a nested array structure. The challenge is maintaining the integrity of the top-level structure while filtering based on data in the second layer. Here's an ex ...

Regular Expressions for Strings in JavaScript

I want to create a regular expression in JavaScript that can search for patterns like ${.............}. For example, if I have a string like { "type" : "id", "id" : ${idOf('/tar/check/inof/high1')}, "details" : [ { ...

Tips for resolving dependency conflicts in a JavaScript project starter template

Currently, I'm utilizing the Airframe React template and the procedure seems quite simple: Extract the files and execute npm install in the project directory. However, an issue arises when running npm install as follows: npm WARN config global `--glob ...

Converting HTML to a Text String (not for display) using Angular

When it comes to displaying HTML in Angular, there are numerous approaches available. For example, using $sce.trustAsHtml(myHtmlVariable) is one way to achieve this. However, I am interested in creating something like the following: myStringVariable = s ...

Is there a way for me to retrieve the name of a newly opened browser tab from the original tab?

I have written a code snippet to create a new tab within the same browser by clicking on a link. function newTab() { var form1 = document.createElement("form"); form1.id = "newTab1" form1.method = "GET"; form1.action = "domainname"; //My ...

The statement "document.getElementById('grand_total_display').innerHTML = "Total is : $"+variable;" is causing issues in Internet Explorer versions 6 and 7

document.getElementById('grand_total_display).innerHTML = "Total is : $"+variable; seems to be causing an error specifically in IE6 and IE7 Within my HTML, I have an element <li> identified as grand_total_display which contains some existing te ...

Learn the technique of coding HTML within inline JavaScript, along with implementing CSS inline styling

I'm looking for a way to incorporate HTML within inline JavaScript, along with CSS inline styles. Can someone provide guidance on how to achieve this? For example, something like the following code snippet: <p><span style="color: #00ff00;"&g ...

What is the best way to compare two arrays of ids in MongoDB to find matching elements?

I have 2 arrays with different ids : bikesWithNoOrders [id , id1 , id2] filteredResult [id3 , id5] Is there a way to query and find all of them at once? This is what I currently have: queryBuilder.find({ _id: { $in: bikesWithNoOrders } }); queryBuilde ...

``The Art of Handling REST API with Express and Mongoose

Running Express on my application, I have a delete route set up as shown below: router.route('/lists/:id') .delete(function(req, res){ Entry.remove({ _id: req.params.id }, function(err, list){ if(err) ...

What is the best way to display the elements of an array within an HTML div element?

I've been trying to display the contents of an array in a div container on my HTML file, but I'm stuck. Here's what I currently have: function printArray() { var $container = $('.container'); $container.html(''); ...

Example of AngularJS UI-Router Login Feature

Currently, I am delving into the realms of angularjs and bootstrap to develop a web application that will consist of two distinct sets of views - public and private. In the public view, all users will have access to it and there will be a specific top men ...