MEAN / AngularJS app检查对象是否已发布

时间:2015-08-28 06:19:08

标签: javascript angularjs node.js mongodb express

我有thig angularJS前端,我在后端使用express,node和mongo。

我的情况如下:

//my data to push on server
$scope.things = [{title:"title", other proprieties}, {title:"title", other proprieties}, {title:"title", other proprieties}]

$scope.update = function() {
    $scope.things.forEach(function(t) {
        Thing.create({
            title: t.title,
            //other values here
        }, function() {
            console.log('Thing added');
        })
    })
};

//where Thing.create its just an $http.post factory

HTML部分如下:

//html part
<button ng-click="update()">Update Thing</button>

然后在同一页面上,用户可以更改$scope.things,我的问题是,当我再次呼叫update()时,所有内容都会被发布两次,因为这就是我正在做的事情。

有人可以解释我如何检查已经发布到服务器的“东西”是否只是为了更新值($ http.put)以及它是否未在服务器上发布到$ http.post。

或者也许是其他方式来做到这一点?

2 个答案:

答案 0 :(得分:2)

我看到了一些决定:

1)您是否应该在用户点击“更新”按钮后发送请求(就像您目前正在做的那样)?或者,如果您在用户更改事物时发送请求(使用ngChange)?

2)如果按下(1)的按钮方法,你应该发送每个Thing的请求(就像你现在正在做的那样),或者你应该首先检查是否已经更新/新建了Thing前端。

3)你怎么能处理这样一个事实:有些东西是新创造的而其他东西只是更新了?多条路线?如果是,那么您如何知道将请求发送到哪条路由?同样的路线?怎么样?

1

对我而言,使用“更新”按钮的好处似乎是用户清楚它是如何工作的。通过点击“更新”(之后可能会看到一条flash消息),用户知道(并获得视觉反馈)Thing已经更新。

使用“更新”按钮的成本是可能会有不必要的请求。网络通信速度很慢,所以如果你有很多事情,那么为每件事做出请求可能会非常慢。

最终,这似乎是我对用户体验与速度的决定。这取决于具体情况和目标,但我个人倾向于“更新”按钮。

2

这里的权衡似乎是代码简单性和性能之间的关系。更简单的解决方案就是为每个Thing提出请求,无论它是否已被更新/新创建(对于以前存在但没有改变的Thing,不会造成任何伤害 - 它们根本不会被更改)

更复杂但更高效的方法是跟踪事物是否已更新/新创建。您可以向Thing's添加一个名为dirty的标记以跟踪此情况。

  • 当用户点击创建新的Thing时,新的Thing将被赋予dirty: true的标记。
  • 当您查询从数据库中获取所有内容时,它们都应该dirty: false(无论您是否要将dirty属性存储在数据库中,或者只是将其附加到服务器/前端结束取决于你)。
  • 当用户更改现有Thing时,dirty属性将设置为true

然后,使用dirty属性,您只能请求dirty的事物:

$scope.things.forEach(function(thing) {
  if (thing.dirty) {
    // make request
  }
});

正确的解决方案取决于您的具体情况,但我倾向于在代码简单性方面犯错误而不是性能。

3

如果您使用的是Mongoose,default behavior就是在创建的文档中添加_id字段(它也是default behavior,也可以是MongoDB本身)。因此,如果您没有覆盖此默认行为,并且如果您没有明确阻止将此_id字段发送回客户端,则它应该存在于先前已创建的Thing中,从而允许您区分他们来自新创造的东西(因为新创造的东西不会有_id字段)。

有了这个,您可以有条件地拨打createupdate,如下:

$scope.things.forEach(function(thing) {
  if (thing._id) {
    Thing.update(thing._id, thing);
  }
  else {
    Thing.create(thing);
  }
});

或者,您可以使用单个路径为您执行“创建或更新”。您可以在{ upsert: true }来电中设置update来完成此操作。

general中,upsert将检查文档是否与查询条件匹配...如果匹配,则更新它,如果没有,则创建它。在您的情况下,您可以在Mongoose findByIdAndUpdate的上下文中使用upsert,如下所示:

Thing.findByIdAndUpdate(id, newThing, { upsert: true }, function(err, doc) {
  ...
});

请参阅this SO post。

答案 1 :(得分:1)

@Adam Zemer巧妙地解决了我在评论中提出的问题,但我对某些观点持不同意见。

首先,要回答是否有更新按钮的问题,你必须问自己。用户是否有理由放弃他的更改并且不保存他所做的工作。如果答案是否定的,那么我很清楚,不应该更新更新,这就是原因。

  1. 为避免您的用户失去工作,您需要在尝试更改页面或关闭浏览器等时添加确认信息。另一方面,如果一切都被持续保存,他可以放心,他的工作是永远保存,你不必实施任何东西,以防止他失去工作。
  2. 你减少了他的工作量,少了点击任务可能看起来微不足道,但他可能会多次点击它确保他的工作保存。此外,如果它是一个经常性的任务,它肯定会改善他的经验。
  3. 明智的性能和代码可读性,您可以执行小的请求,而不必实现任何复杂的逻辑。简单的输入改变。
  4. 为了向他明确表示他的工作会不断保存,您只需说出所有更改已保存并将其更改为保存更改... 发出请求。例如,请查看在线办公室或谷歌文档。
  5. 然后,您只需使用mongoDB查询中的upsert参数即可使用单个请求创建和更新您的内容。以下是控制器的外观。

    $scope.update = function(changedThing) { // Using the ng-change you send the thing itself in parammeter
        var $scope.saving = true; // To display the saving... message
        Thing.update({ // This service call your method that update with upsert
            title: changedThing.title,
            //other values here
        }).then( // If you made an http request, I suppose it returns a promise.
               function success() {
                   $scope.saving = false;
                   console.log('Thing added');
               },
               function error() {
                   //handle errors               
               })
    };