2

I'm creating an order form and a schema defined for an Order (certain required fields such as address, customer info, items selected and their quantities, etc).

a. User visits site.

b. A unique ID is generated for their session as well as a timestamp.

var userSession = {
  _id: createId(),
  timestamp: new Date(),
};

var sessionId = userSession._id;

c. The userSession is placed in local storage.

storeInLocalStorage('blahblah', sessionObject);

d. An Order object is created with the sessionId as the only field so far.

var newOrder = {
  sessionId: sessionId;
};

e. Obviously at this point the Order object won't validate according to the schema so I can't store it in Mongo. BUT I still want to store it in Mongo so I can later retrieve incomplete orders, or orders in progress, using the sessionID generated on the user's initial visit.

This won't work because it fails validation:

Orders.insert(newOrder);

f. When a user revisits the site I want to be able to get the incomplete order from Mongo and resume:

var sessionId = getLocalStorage('blahblah')._id;
var incompleteOrder = Orders.findOne({'sessionId', sessionId});

So I'm not sure how to go about doing this while accomplishing these points.

  • I want full simpleschema validation on the Orders collection when the user is entering in items on the forms and when the user is intending to submit a full, complete order.

  • I want to disable simpleschema validation on the Orders collection and still allow storing into the DB so that partial orders can be stored for resumption at a later time.

I can make a field conditionally required using this here but that would mean 50+ fields would be conditionally required just for this scenario and that seems super cumbersome.

fuzzybabybunny
  • 5,146
  • 6
  • 32
  • 58

4 Answers4

1

It sounds like you want to have your cake, and eat it too!

I think the best approach here would be keep your schema and validation on the Orders collection, but store incomplete orders elsewhere.
You could store them in another collection (with a more relaxed schema) if you want them on the server (possibly for enabling resume on another device for the logged in user) , or more simply in Local Storage, and still enable the resume previous order behaviour you are wanting.
Only write to the Orders collection when the order is complete (and passes validation).

JeremyK
  • 3,240
  • 1
  • 11
  • 24
  • Yeah, I've been fiddling around with the idea of storing incomplete orders elsewhere. Guhhhhh.... added code. Added complexity. More functions to coordinate together. I already tried just storing the entire thing in Local Storage, but because Local Storage only supports items that can be serialized, you have to do additional work to the object after you retrieve it from Local Storage (Numbers become strings, Date objects becomes just a string, etc) to convert it *back* to something you can use. It's a pain in the ass. – fuzzybabybunny Oct 02 '15 at 03:42
  • Check if EJSON.stringify / EJSON.parse will handle your datatypes for serializing and parsing your data. 'meteor add ejson' if it's not already part of your project. – JeremyK Oct 02 '15 at 04:07
1

Here's a variation on @JeremyK's answer: add an inProgress key to your order of type [Object]. This object would have no deeper validation. Keep your in progress order data in there until the order is final then copy/move all the relevant data into the permanent keys and remove the inProgress key. This would require that you make all the real keys optional of course. The advantage is that the object would maintain its primary key throughout the life cycle.

Michel Floyd
  • 18,793
  • 4
  • 24
  • 39
  • Very clever way of going about it! – fuzzybabybunny Oct 03 '15 at 21:59
  • Unless you explicitly delete the _id value from the InProgress collection before inserting it into the Orders collection, you will retain the same primary key by default (and retain a schema with non-optional values). i.e. you can supply the _id value (assuming that's the primary key you are referring to) to a Collection.Insert call, and it will use it rather than generate a new one. It will fail though if you try to enter an object with a _id value that already exists, but if you only ever use _id values generated by the InProgress.Insert call this will not happen. – JeremyK Oct 03 '15 at 22:18
1

I think this particular case has been solved; but just in case, you can skip Simple Schemma validations by accessing MongoDB native API via Collection#rawCollection():

Orders.rawCollection().insert(newOrder);
jmendiola
  • 403
  • 3
  • 8
0

While this question is very old in the meantime there is a better solution. You probably use simple schema together with collection2. Collection2 has the ability to set multiple schemas based on a selector and then validate against the correct schema based on it.

https://github.com/Meteor-Community-Packages/meteor-collection2#attaching-multiple-schemas-to-the-same-collection

e.g. you could have a selector {state: 'finished'} and only apply the full schema to these documents while having another selctor, e.g. {state: 'in-progress'} for unfinished orders with a schema with optional fields.

Tobi
  • 1,175
  • 1
  • 19
  • 44