(SOLVED) Custom non-reactive publication


#1

Hello,

In eshop we have Product view and in mongo product document we have property - array of accessories _id’s.
I need to call subscribe with argument ( our main product _id) and get back max 3 documents from each category :smiley: Cause we are not going to show more in this view.

For now I am thinking about this approach:
findOne that main product _id, get accessoriesList from it
Products.find where _id is in accessoriesList
Than want to transform results by aggregate
And than publish them using publish low level API to custom clientside collection.

Am I thinking in the right direction?
@awatson1978


#2

As usual, standard pipeline aggregation could not solve it easily as it does not support $limit per key
So I added mapReduce to meteorhacks:meteor-aggregate package and submitted PR for review https://github.com/ShockiTV/meteor-aggregate
And now back to working directly on our eshop project.


#3

Sooo, end result
warning: coffeescript :smiley:
I have custom client side collection to hold results

@Accessories = new Mongo.Collection('accessories')

Subscribing to it from template

Template.productAccessories.onCreated ->
  @contentSub = @subscribe "productAccessories", @data._id

And that ugly publication with mapReduce

Meteor.publish 'productAccessories', (productId) ->
  currentProduct = MasterProducts.findOne({
    _id: productId
    },
    field:
      accessories: 1
  )

  if not currentProduct?
    @ready()
    return

  accessoriesList = currentProduct.accessories

  if accessoriesList.length is 0
    @ready()
    return

  mapFunction1 = () ->
    emit(@category,
      _id: @_id
      product: @product
    )

  reduceFunction1 = (keyGroup, valuesItems) ->
    if valuesItems.length > 3
      return {results: valuesItems[0...3]}
    else
      return {results: valuesItems}

  finalizeFunction = (key, value) ->
    # return array even in case of single string value
    # cause single value is not passed to reduce function
    if value.results?
      return value.results
    else
      return [ value ]

  reduceResult = MasterProducts.mapReduce(
    mapFunction1,
    reduceFunction1,
      out:
        inline: 1
      query:
        _id:
          $in: accessoriesList
      finalize: finalizeFunction
  )

  @added("accessories", 'test', reduceResult)
  @ready()