Giter Site home page Giter Site logo

Comments (9)

deontologician avatar deontologician commented on July 16, 2024 2

Aggregate

You can now aggregate horizon queries together like this:

let horizon = Horizon()
let aggregated = horizon.aggregate({
  owner: horizon('people').find('bob'),
  pet: horizon('animals').find('spot'),
  related: {
    friends: horizon('people').findAll({friendOf: 'bob'}).limit(10),
    petFriends: horizon('animals').findAll({friendOf: 'spot'}).limit(10),
  },
  someConstant: "Always have this here",
  petsAndOwners: [ hz('pets'), hz('owners') ] // this is nonsensical, but you know, example
})

You can now call .fetch() or .watch() on the aggregate, and it will do what you expect. With .watch(), it will internally emit a new document any time any sub-query receives a change, it caches the results of all other subqueries and re-emits them.

Aggregates can be composed of several things:

  • Objects, like in the example above
  • Arrays: aggregate([hz('foo'), hz('bar')]) will result in an array that has the results of the foo and bar tables flattened into one. There's no guarantee on ordering.
  • Literals: null, numbers, strings, booleans, Dates and ArrayBuffers can be put into aggregates and they'll be emitted as-is in the final datastructure. (Arrays and objects that contain literals will be emitted as-is, so this works as you'd expect: hz.aggregate([1, true, 'bob']).fetch() -> [1, true, 'bob']
  • Horizon queries: hz.aggregate(hz('foo').find(2)) is equivalent to hz('foo').find(2)
  • Observables: they'll be emitted with whatever behavior they already have, so there's no difference for them between .fetch() and .watch(). This can be helpful if you want to update a counter or the like:
hz.aggregate({
  counter: Observable.timer(0, 1000),
  someQuery: hz('foo').find('bar'),
}).watch().subscribe({ next(x){ console.log(x) }})

Every second (or whenever the someQuery gets a change), the entire datastructure will be re-emitted with an incremented counter.

You can also nest aggregates, like:

hz.aggregate({
  foo: hz.aggregate({ ... })
})

But this isn't super useful, since it's equivalent to just doing:

hz.aggregate({
  foo: { ... }
})

Model

You can also parameterize aggregates using the model method. It's fairly simple and just allows a convenient syntax for creating templates for aggregates:

const MyModel = hz.model((a, b, c) => {
  return {
    foo: hz('foo').find(a),
    bar: hz('bar').find(b),
    baz: hz('baz').find(c),
  }
})
// Sometime later, use it

var modelA = MyModel(1, 2, 3)
var modelB = MyModel(2, 3, 4)
modelInstance.fetch().subscribe(x => console.log(x))

You can do anything you can do with aggregates here, but it's worth mentioning you can also nest models (which will seem maybe more useful than nesting aggregates, even though it's equivalent):

const Pet = hz.model(petId => hz('pets').find(petId)) // note you can aggregate a bare query
const Owner = hz.model( ownerId => hz('owners').find(ownerId) )
const PetAndOwner = hz.model((petId, ownerId) => {
  pet: Pet(petId),
  owner: Owner(ownerId),
})
var marcAndSkyla = PetAndOwner('skyla', 'marc')
var dalanAndRes = PetAndOwner('res', 'dalan')
marcAndSkyla.fetch()
dalanAndRes.watch()

from horizon-docs.

deontologician avatar deontologician commented on July 16, 2024 1

Sounds good, I'll change it. We already have a way to union queries anyway (hz('foo').fetch().merge(hz('bar').fetch())), so a special syntax for it isn't really warranted probably.

I would like to take this moment to grumble that it's more work for me

from horizon-docs.

deontologician avatar deontologician commented on July 16, 2024

Marshall also made Promises work in aggregates, so that's allowed now too

from horizon-docs.

mlucy avatar mlucy commented on July 16, 2024

@deontologician --

Arrays: aggregate([hz('foo'), hz('bar')]) will result in an array that has the results of the foo and bar tables flattened into one. There's no guarantee on ordering.

What's the behavior .aggregate([1, hz('bar')])?

What about.aggregate([[1, 2], hz('bar')])?

What about.aggregate([[1, 2], hz('bar'), hz('foo')])?

What about.aggregate([[1, 2], hz('bar'), [3, 4], hz('foo')])?

Is there any way to get back an array containing two arrays each of which comes from a Horizon query (i.e. to get [[foo1, foo2, ...], [bar1, bar2, ...]] instead of [foo1, bar1, foo2, bar2, ...])?

(Also, are we super attached to the fact thathorizon.aggregate([FOO, BAR]) does an implicit union of the two streams? That seems kind of wacky to me, especially because it looks like we aren't implicitly unioning non-Horizon objects when they're put inside the same syntax. I would expect hz.aggregate([FOO, BAR]) to give me the [[foo1, foo2, ...], [bar1, bar2, ...]] shape. Another option would be to make hz.aggregate([FOO, BAR]) return [[foo1, foo2, ...], [bar1, bar2, ...]] and hz.aggregate(FOO, BAR) return [foo1, bar2, foo2, bar2, ...].)

from horizon-docs.

mlucy avatar mlucy commented on July 16, 2024

Actually, thinking about it more, it seems kinda bad that hz.aggregate([FOO, BAR]) does an implicit union. For everything else we seem to have the property the hz.aggregate(f(FOO)) is analogous to FOO.fetch().subscribe(x => hz.aggregate(f(x))) (ignoring the updating). Doing an implicit union for Horizon queries but not for other objects breaks that property.

from horizon-docs.

chipotle avatar chipotle commented on July 16, 2024

So just so I'm clear, this is a method on the Horizon object, not Collection (because it operates on multiple collections).

from horizon-docs.

deontologician avatar deontologician commented on July 16, 2024

Right, the horizon toplevel object itself

from horizon-docs.

geddski avatar geddski commented on July 16, 2024

So. Freaking. Great.

from horizon-docs.

chipotle avatar chipotle commented on July 16, 2024

(Since this is merged into the horizon-2.0 branch I'm closing this issue.)

from horizon-docs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.