简体   繁体   English

在创建数千个子记录后,Ember.js / Ember Data需要几分钟才能更新hasMany的父级

[英]Ember.js/Ember Data takes several minutes to update hasMany of parent after creating thousands of child records

I'm new to Ember.js and running into performance issues when trying to create thousands of records (5300 to be exact) and updating a hasMany relationship. 我是Ember.js的新手,在尝试创建数千条记录(确切地说是5300)并更新hasMany关系时会遇到性能问题。 I'm making a request to my API to retrieve records before I create my new records. 在创建新记录之前,我正在向API请求检索记录。 After the promise returns, I then do a forEach over each record brought down (5300) to do my calculations for the new set of records. 在承诺返回之后,我然后对每个记录下来的记录(5300)执行forEach以对新记录集进行计算。 Creating the records themselves takes about 2 seconds. 创建记录本身大约需要2秒钟。 Updating the hasMany starts off quickly only for the first 40 or so records and then slows to about one update per second. 更新hasMany仅对前40个左右的记录快速启动,然后减慢到每秒约一个更新。

I should also note that this is being done within a component. 我还应该注意到,这是在一个组件内完成的。 I know this is typically anit-pattern, but in this case there is no reason to change the URL or transition. 我知道这通常是anit-pattern,但在这种情况下,没有理由更改URL或转换。 This is a screen where users can select from a pool of items (provided by the route), apply a pricing rule, and then create an event (created in the route) based on those items. 这是一个屏幕,用户可以从一个项目池(由路径提供)中进行选择,应用定价规则,然后根据这些项目创建一个事件(在路径中创建)。 It's a sandbox to determine what items will be a part of the event. 这是一个沙箱,用于确定哪些项目将成为活动的一部分。 Once the users have decided on their items for the event, I then send an action up to the route to perform the actual save and persist to my backend. 一旦用户决定了他们的活动项目,我就会向该路线发送一个动作来执行实际的保存并持续到我的后端。 Outside of the anti-pattern aspect, I can't see how this would affect the performance of the hasMany update. 在反模式方面之外,我无法看到这将如何影响hasMany更新的性能。

I'm using RESTAdapter and RESTSerializer for what it's worth, but that should not have any impact here since I'm just dealing with the Ember data store. 我正在使用RESTAdapter和RESTSerializer来获取它的价值,但这不应该对我有任何影响,因为我只是处理Ember数据存储。

Ember Version: 灰烬版:

Ember             : 2.5.1
Ember Data        : 2.5.3
jQuery            : 2.2.3
Ember Simple Auth : 1.1.0

The two models in question are as follows... 有问题的两个模型如下......

Child Model (event-item): 儿童模特(事件项目):

export default DS.Model.extend({
  event: DS.belongsTo('event'),
  itemNumber: DS.attr('string'),
  styleNumber: DS.attr('string'),
  tier: DS.attr('string'),
  eventPrice: DS.attr('number')
});

Parent Model (event): 父模型(事件):

export default DS.Model.extend({
  eventTypeId: DS.attr('string'),
  eventName: DS.attr('string'),
  eventDesc: DS.attr('string'),
  startDate: DS.attr('moment-date'),
  endDate: DS.attr('moment-date'),
  priority: DS.attr('number'),
  statusCode: DS.attr('string'),
  value: DS.attr('number'),
  eventItems: DS.hasMany('event-item', {async:true})
});

Event create record: 活动创建记录:

model() {
    return this.store.createRecord('event', {});
},

Code block in component responsible for creating records and updating hasMany: 负责创建记录和更新hasMany的组件中的代码块:

this.get('store').query('pricing', {brandCd: '00'}).then(tiers => {
    tiers.forEach(tier => {
        this.get('event').get('eventItems').createRecord({
            styleNumber: tier.get('styleNumber'),
            itemNumber: tier.get('itemNumber'),
            brandCd: '00',
            tier: tier.get('tier'),
            eventPrice: this._calculateEventPrice(tier.get('origPrice'), this.get('event').get('eventTypeId'), this.get('event').get('value')),
        });
    });

    this.get('event').set('needsUpdated', 'Y');
});

So far I've tried the following... 到目前为止,我已尝试过以下内容......

  • Adding inverse relationships to my hasMany and belongsTo 添加与我的hasMany和belongsTo的反向关系
  • Adding all of the create records to an Ember.A() and then trying to push the new records to the hasMany like so: this.get('event').get('eventItems').pushObjects(newEventItems); 将所有创建记录添加到Ember.A() ,然后尝试将新记录推送到hasMany,如下所示: this.get('event').get('eventItems').pushObjects(newEventItems); . Also tried it using this.get('event').get('eventItems').addObjects(newEventItems); 还尝试使用this.get('event').get('eventItems').addObjects(newEventItems); .
  • Setting the belongsTo on the record being created instead of updating the hasMany of the parent (event). 在正在创建的记录上设置belongsTo,而不是更新父(事件)的hasMany。
  • I also went ahead and moved this logic into my route just to make sure I wasn't getting odd behavior by doing this in the component. 我也继续前进并将这个逻辑移到我的路线中,以确保我在组件中执行此操作时没有得到奇怪的行为。 It performs the same. 它执行相同的操作。

I would assume (and please correct me if I'm wrong) that creating records and updating relationships strictly on the client side should be able to handle thousands of records without too much issue. 我认为(如果我错了请纠正我),严格在客户端创建记录和更新关系应该能够处理数千条记录而不会出现太多问题。 I'm hoping I'm just doing something incorrect or in an inefficient way that will be obvious to someone with more experience. 我希望我只是做一些不正确的事情,或者以一种效率低下的方式对那些经验丰富的人来说是显而易见的。 Any help, including alternatives, is greatly appreciated! 任何帮助,包括替代品,非常感谢!

I've found working with large sets of 'hasMany' relationships to be slow as well. 我发现使用大量'hasMany'关系也很慢。

My advice: Build the relationship on the server with a custom endpoint, and communicate the changes back to the client over websockets. 我的建议:使用自定义端点在服务器上构建关系,并通过websockets将更改传回客户端。 Trying to individually save 5300 records in Ember will make 5300 network requests, whereas this could be accomplished in 1 outbound request, and possibly one websockets message, though it might be advisable to batch the responses in smaller sets. 尝试在Ember中单独保存5300条记录将产生5300个网络请求,而这可以在1个出站请求中完成,可能还有一个websockets消息,尽管建议将响应批量处理为较小的集合。

No need to make the relationships in Ember until the changes are committed. 在更改提交之前,无需在Ember中建立关系。 The returned websockets message should include the relationship's foreign keys Ember Data needs to construct the relationships. 返回的websockets消息应该包含关系的外键Ember Data需要构建关系。

This means that up front, you'll be creating eventItems (or whatever your model is called) without a parent. 这意味着,在没有父级的情况下,您将创建eventItems (或任何模型被调用)。

Finally, you might consider creating the child records on demand, instead of trying to create every child item for the user right away. 最后,您可以考虑按需创建子记录,而不是尝试立即为用户创建每个子项。 Just do the createRecord when a user decides to select the item from the pool of items. 当用户决定从项目池中选择项目时,只需执行createRecord (Hopefully I'm understanding your use case correctly.) If you take that approach, you might not even need to use a custom endpoint as I've described. (希望我能正确理解你的用例。)如果采用这种方法,你甚至可能根本不需要使用我所描述的自定义端点。

Last bit of advice: Your note about 'anti-patterns' is correct: NEVER do CRUD operations, or anything really async, in components, especially not for 5300 items . 最后一点建议:你关于'反模式'的说明是正确的:永远不要在组件中进行CRUD操作或任何真正的异步操作, 特别是对于5300项 Components can easily be torn down before an async operation completes, leaving your application in a weird state, and most likely resulting in bugs. 在异步操作完成之前,可以轻松地拆除组件,使应用程序处于奇怪的状态,并且很可能导致错误。 Move whatever you do into the route, like you said, and stick with that pattern. 像你说的那样将你做的任何事情移动到路线中,并坚持使用那种模式。 Components should just be "dumb" templates that display stuff and send actions. 组件应该只是“哑”模板,显示东西和发送动作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM