Hackpads are smart collaborative documents. .

Andrew Mao

1254 days ago
Unfiled. Edited by Andrew Mao 1254 days ago
Andrew M
  • The approach in this document seems to only work with documents that are bound directly to DOM elements. It doesn't work when data is post-processed with `d3.nest` followed by a `d3.layout`, for example - which are often required for more advanced aggregate visualizations. However, doing the aggregate operations continuously may be doable if the underlying data array is updated efficiently; see comment below.
  • This seems like it will only work with very small datasets. `cursor.fetch()` deep copies all documents when it is called, so this will be extremely slow. It seems like the best approach is to create a single reactive array that is updated using `cursor.observe`, specifically using the `addedAt` and `removedAt` callbacks, which can then be repeatedly joined with `selection.data` in D3. This basically accomplishes the same effect as repeatedly calling `fetch()` without the huge CPU and memory usage of a large collection, and could be easily implemented as part of a d3 helpers package.
  • As I mentioned above, I think an efficiently updated array is the best of both worlds. This approach doesn't allow writing code using d3's data join syntax, which makes it concise and easy to express data-driven changes. It results in a lot more code and is harder to maintain.
1289 days ago
Unfiled. Edited by Nate Strauser , Avital Oliver , Andrew Mao , Slava Kim 1289 days ago
In any JavaScript console, you can create a new Date, representing the current date and time, then inspect some of its properties.
  • var date = new Date();  //create a new date with current date and time
See the Mozilla docs on Date for more examples.
Nate S
  • Dates are Displayed in Local Timezone by Default
Whenever you display a Date, it will be translated into the local timezone of the device by default.   The examples above clearly indicate they are in Eastern Time, which is correct as the code was run on a device in that timezone.  If you are in a different timezone, your output should differ from the above and match your device's location.
  • 1. Storing Dates
The best way to represent dates on your collection documents is by directly using the Date object type.  You can store Date objects directly into collection documents.  If we are creating a document, we can generate a Date object as one of the properties supplied to the collection's `insert()` method.
It is easy to create a Date object on the client and store it, using a client side `insert()` as shown above.  While this is acceptable for simple projects, when building a real world application you’ll want to ensure the integrity of your Dates by only generating them on your sever.  The only clock that we can trust is the server clock. Clients can not be trusted.  A user might set the clock wrong (accidentally or maliciously) or it might be out of sync.  It is important that Dates be generated only by a server clock that you can trust. 
Andrew M TimeSync
The timesync package computes an accurate server time on the client, in most cases to within 100ms of accuracy, and additionally provides reactive variables for using time on the client. It can be used to generate timestamps on the client where the accuracy of immediate generation is more important than the authoritativeness of the server time, and when absolute security isn't critical. For example, it is used by the user-status package for accounting of when users do things in their browser, and when they are idle - without needing round trips to the server. The traffic saved by having a client-local server time outweighs the security concerns for timestamps that aren't used for authentication or other important purposes.
To use this package, install it with Meteorite:
  • mrt add timesync
and then use TimeSync.serverTime() to get the server's current time on the client. This function returns a timestamp rather than a Date object, as it's computed from the server offset. To get a date, simply use the constructor new Date(TimeSync.serverTime()).
By default, TimeSync.serverTime() is reactive - it updates in real time in your app, at a default rate of once per second. This makes it possible to show continually updated time in your app, and use server-relative timestamps everywhere. For more advanced usage, check out the docs.
Nate S
  • i had considered timesync initially, but left it out since it returns a numerical value, which is counter to our general 'use date objects' message - maybe this should be an alternative?
Andrew M
  • Because it's computed from an offset, the numerical value is the lowest-level thing to return. I considered wrapping every function return in a date but decided against it at the time. Perhaps it's better to do that though, it's probably premature optimization.
Nate S
  • ok - not against this at all, just thinking we'll want to use it in the context of a native Date object, (get the offset, create a date object from it) and present it later in the document (near the collection2 option)
Andrew M
  • I'm happy to implement a TimeSync.serverDate() method that wraps the serverTime() method and push it right now, if you want. I don't see this belonging all the way down there as it follows immediately from your security warning paragraph
Nate S
  • if you want to alter the package, go for it - its also very simple to just do new Date(TimeSync.serverTime()) --- from my talks with matt, we're trying to present very few options, then alternatives - trying to not present readers with too many options up front
Andrew M
  • Sure, you should move it down then. I am visiting MDG next week and maybe we'll talk about stuff.
Nate S
  • ok - thanks for adding this
Collection Hooks
The best mechanism for ensuring accurate creation/insert dates on your documents is to use the collection-hooks package as it provides the least intrusive option for ensuring Date integrity on your documents.
Andrew M
  • Hey guys, how about some love for collection-hooks by considering a roadmap for getting it into core? David Glasser shot this down before at meteor/meteor#395, but considering how you've written this whole page and how the current monkey-patched solution is both hard to test and receives little attention in comparison to its usage base, I think it would be important to have wider support and a more robust implementation for it. We wouldn't want another OpenSSL :)
Slava K
  • how should it work on multi-server setting? 
Andrew M
  • I don't know how much you guys test multi-server settings, but I think you would need a good distributed systems expert. I've consider this for https://github.com/mizzao/meteor-user-status as well. Basically, we need an API where servers can transparently do elections to run functions that only happen once across the cluster. Total orderings, failover, etc.
  • re: having it in Galaxy - so we really need a core supported collection hooks that hooks into this API then. I'm going to be at your office next week, we should chat about this.
Nate S To use collection-hooks, you'll need to first add the package to your application.
  • mrt add collection-hooks
This will expose `before` and `after` hooks on all collections for insert, update, and remove operations.
Nate S
  • Be careful to define your hooks in the correct location as hooks work can be defined on the client, server or both. Without the `Meteor.isServer` wrapper or placing the code in the `server/` folder of your app (eg `server/hooks.js`), you could be still using the client's clock to generate the Date.
Meteor Methods
The collection-hooks package works well if your application does client side inserts/updates However, if your application already utilizes Meteor methods to perform inserts/updates, generating a Date within the method may be more suitable for your needs.
Any inserts performed that do not use the method, may not have the correct date or even have a Date at all.  If you are utilizing methods to generate dates, you must avoid client side inserts and always use the method.
  • if(Meteor.isServer){
  •   // ensure createdAt date on insert
  •   Things.before.insert(function(userId, doc){
  •      doc.createdAt = new Date();
  •   });
  •   // ensure updatedAt date on update
  •   Things.before.update(function (userId, doc, fieldNames, modifier, options) {
  •       modifier.$set = modifier.$set || {};
  •       modifier.$set.updatedAt = new Date();
  •   });
  • }
Defining hooks like this for each of your collections will allow you to always have correct and reliable dates for your documents. This approach is highly recommended as you can create these hooks once, then just rely on them being set and accurate throughout your application.
As these are quite limited, we recommend using the moment.js package as it provides an easy to use interface for parsing, formatting and manipulating dates.
Add moment to your application, which will expose `moment` on both client and server.
  • mrt add moment
Once we have moment available, we can format Date objects easily into a variety readable options.
  • var date = new Date();
  • moment(date).format('l LT'); //shorthand for localized format
  • // "6/4/2014 3:12 PM"
  • moment(date).format("dddd, MMMM Do YYYY, h:mm:ss a");
  • // "Wednesday, June 4th 2014, 3:12:36 pm"
  • moment(date).format("MMM Do YY");
  • // "Jun 4th 14"
  • //less formal formats, relative to current time
  • moment(date).fromNow();
  • // "a minute ago"
  • moment(date).calendar();
  • // "Today at 3:12 PM"
889 days ago
Unfiled. Edited by Andrew Mao 889 days ago
Andrew M
  • What's the right way to do this with ES6 static functions inside classes? I haven't been able to get anything to work except by using @function, which is just extra mumbo jumbo.
1242 days ago
Unfiled. Edited by Andrew Mao , emgee 1242 days ago
Meteor promises repeatable builds for packages, as well as apps -- if, say, you built your package on a machine, then checked the code into a repository and checked it out elsewhere, you should get the same result. For an app, we ensure consistency across builds by storing the dependency versions used to build the app in the .meteor/versions file. For a package, we do something similar with the versions.json file. Once you build your meteor package (by running tests, adding it to an app, etc), you will find a versions.json file in the package director. That file is part of the source. Check it into version control to ensure repeatable builds across machines.
Sometimes, packages do not just stand on their own, but function in the context of an app (specifically, packages in the packages directory of an app). In that case, the app's context will take precedence. Rather than using the versions.json file as a guide, we will build the package with the same dependencies as used by the app (we think that, in practice, it would be confusing to find your local packages built with different versions of things). However, we will still write the versions.json file. So, for example, if there is a package requiring coffeescript 1.0.0 or above, in an app that uses coffeescript 1.0.1, we will build the package with coffeescript 1.0.1, and we will note this in the versions.json file. (An example consequence, is that, if you are using an app to test a package, it becomes obvious when the app uses different dependency versions than intended. This is particularly useful if you are symlinking a package into two different apps.)
  • I think you should be able to symlink your package into your app's packages directory. Let me know if that's not the case.
Andrew M
  • Meteorite has the ability to install a local filesystem package with `{path: "../some-package"}`, creating the symlink. This is really useful for development, such as for when one creates a meta-repo with a bunch of submodules. It will be a pain to have to manually symlink packages ourselves. Also related: creating demo apps for packages that are published, which usually symlink to `..`.
Andrew W
  • We could use a convention for indicating *which* version of the third party package is being repackaged.  There are several packages on Atmosphere repackaging libraries where it's hard to find out which version of the library is included.  Simply using the third party library version as the Meteor package version doesn't work because there may multiple versions of the repackaging (e.g., I publish a repackaging of Foo 1.2.3, but then realize I didn't do it in the best way, and so publish a new version of the republishing package which needs a new version number, but I'm still repackaging Foo 1.2.3); and the third party library may not necessarily be using semantic versioning.
Andrew M
  • I've generally published simple wrapper packages with the same version as the wrapped package; for packages that provide more functionality, I use my own versioning. Semver will also allow the `+blahblah` suffix string on the end for metadata, so that could be a convention to specify the wrapped package version.
1289 days ago

Contact Support

Please check out our How-to Guide and FAQ first to see if your question is already answered! :)

If you have a feature request, please add it to this pad. Thanks!

Log in