# Count async hasMany without loading

**URL:** <https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751>\
**Category:** Ember Data\
**Created:** [April 8, 2015, 11:16pm UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751 "2015-04-08T23:16:08Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![H1D](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/h1d/32/15291_2.png) [@H1D](https://discuss.emberjs.com/u/H1D)\
**Post date:** [April 8, 2015, 11:16pm UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/1 "2015-04-08T23:16:08Z")

</div>

How can I count related objects associated via hasMany without loading all them? Naive `post.get('comments.length')` would first load all comments. I used to do `post.get('data.comments.length')` but now `data` is deprecated =(

I know about `post._data` but now I’m afarid to use it (after they added that underscore 😃 )

---

<div class="post-metadata">

**Author:** ![H1D](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/h1d/32/15291_2.png) [@H1D](https://discuss.emberjs.com/u/H1D)\
**Post date:** [April 16, 2015, 3:14pm UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/3 "2015-04-16T15:14:41Z")

</div>

Have another problem… How to check if there is associated model (belongsTo)?!

```
{{#if comment.post}}
  comment.parent will be loaded to display this =(
{{/if}}

{{#if comment.post.id}}
  comment.parent still will be loaded to display this =(
{{/if}}

```

This also loads `post` model: `hasPost: Ember.computed.notEmpty('post')`

The only workaround is to use `_data` =(

---

<div class="post-metadata">

**Author:** ![H1D](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/h1d/32/15291_2.png) [@H1D](https://discuss.emberjs.com/u/H1D)\
**Post date:** [April 17, 2015, 11:47am UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/4 "2015-04-17T11:47:21Z")

</div>

Here is my dirty workaround. I tweaked serializer:

```coffeescript
ApplicationSerializer = DS.RESTSerializer.extend
  normalize: (type, hash, prop)->
    # itarate over properties came from payload
    for key, value of hash
      try
        meta = type.metaForProperty(key)
      catch e
        # some keys absent in type class
        continue
      injectProperty = (key, value, attr_type)->
        if not hash[key]
          try
            # absent property will throw Error
            meta = type.metaForProperty(key)
            # this type already extended with that property
            if meta.type is attr_type
              hash[key] = value
          catch e
            hash[key] = value
            tmp = {}
            tmp[key] = DS.attr(attr_type)
            type.reopen tmp
      switch meta.kind
        when 'hasMany'
          # create an array for 'hasMany'
          injectProperty "#{key}_ids", value.slice(), 'array'
          injectProperty "has_#{key}", !!value.length, 'boolean'
        when 'belongsTo'
          # create and XXX_id and has_XXX for 'belongsTo'
          injectProperty "#{key}_id", value, 'string'
          injectProperty "has_#{key}", !!value, 'boolean'
    return @_super.apply @, arguments 

```

This tweaked serialized let’s you check if relationship on a model empty or not without loading associated models, as a bonus you can get ids for associated models.

**models**

```coffeescript
App.Post = DS.model.extend
  text: DS.attr 'string'
  comments: DS.hasMany 'comment', async: true

App.Comment = DS.model.extend
  text: DS.attr 'string'
  post: DS.belongsTo 'post', async: true

```

**usage**

```handlebars
{{#if post.has_comments}}
  This post has {{post.comments_ids.length}} comments
{{/if}}

```

```handlebars
{{#if comment.has_post}}
  This comment associated with post #{{comment.post_id}}
{{/if}}

```

---

<div class="post-metadata">

**Author:** ![nandosan](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/nandosan/32/267_2.png) [@nandosan](https://discuss.emberjs.com/u/nandosan)\
**Post date:** [April 21, 2015, 11:00am UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/5 "2015-04-21T11:00:28Z")

</div>

Really interesting solution. So, your backend is always returning all the ids and you’re dealing with them on client side while still having the metadata for the general type available.

Have you considered possible decrease in performance when dealing with large set of models? (I know ember-data is not the best solution in this scenario anyway…)

I’m going to try it as soon as possible, thanks for sharing!

---

<div class="post-metadata">

**Author:** ![H1D](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/h1d/32/15291_2.png) [@H1D](https://discuss.emberjs.com/u/H1D)\
**Post date:** [April 21, 2015, 2:12pm UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/6 "2015-04-21T14:12:49Z")

</div>

In cases when ids list may be large (for example comments) we introduce proxy model:

```coffeescript
App.Step = DS.Model.extend
  comment_proxy: DS.belongsTo 'comment-proxy', async: true
  comments_count: DS.attr 'number'

App.CommentProxy = DS.Model.extend
  comments: DS.hasMany 'comment', async: true

App.Comment = DS.Model.extend
  text: DS.attr 'string'
  target: DS.belongsTo 'step', async: true

```

So we load `comment_proxy` only when user want to interact with comments. Yes It can be slow. We have item with \>3200 comments check out numbers:

- `comment_proxy` payload is about 14kb
- it takes about 4 seconds to show comments after user pressed “show comments button”

Of course we do not load all 3200 comments, only first 17 comments will be loaded.

Anyway we need all ids on client-side to implements permalinks. Here is why: imagine someone linked 3200th comment – you dont want to load ALL comments, so our solution is to extract subarray with linked ID and few siblings load only them and display.

BTW discourse have similar solution! Here are 40k+ comments thread – [Login to your account - What the Daily WTF?](http://what.thedailywtf.com/t/the-thread-of/1000/10465) you can open devtools and then try to load this page

---

<div class="post-metadata">

**Author:** ![remkoboschker](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/remkoboschker/32/11466_2.png) [@remkoboschker](https://discuss.emberjs.com/u/remkoboschker)\
**Post date:** [March 30, 2016, 7:54am UTC](https://discuss.emberjs.com/t/count-async-hasmany-without-loading/7751/7 "2016-03-30T07:54:19Z")

</div>

You can check the new references api [Ember Data 2.4 and 2.5 Beta Released](http://emberjs.com/blog/2016/03/13/ember-data-2-4-released.html#toc_code-ds-references-code)
