Storing many to one objects in simpleschema mongo collection


#1

How would I be able to structure a one to many relationship with document embedding or document referencing in meteor? I am using the simpleschema package and require to save an array of objects within a field.

So for example I have a invoice and I want to attached the individual products from the order.

So invoice -> productIds -> product data is the mapping. What do I set the field type to in simpleschema, can anyone provide a small example so I can get my head around this. I have read a lot that 1:n modelling is possible in Mongo and meteor although there are the composite publish package that can help retrieve children. The only part of the puzzle i’m missing is how actually to legitimately insert (as in embed or reference) multiple objects to a document

Thanks in advance for any help on this


#2

I’ve been studying the telescope source and see they achieve it via using _.pluck and a simple schema as so

/**
 An array containing posts downvotes
  */
 downvotedPosts: {
    type: [Telescope.schemas.votes],

Insertion is done via a $addToSet

How would I use $addToSet with a autoform insert form; so that I could store embedded document ids to link a one to many relation in my data model?


#3

I have this on my project, it basically works like this:

const LineItem = new SimpleSchema({
  'productId': {
    type: String,
    allowedValues() {
      return Products.find().map(s => s._id);
    }
  },
  'quantity': {
    type: Number,
    defaultValue: 1,
    min: 1
  }
});

Orders.attachSchema(new SimpleSchema({
  'products': { type: [Object] },
  'products.$': { type: LineItem },
  'subtotal': {
    type: Number,
    decimal: true,
    autoValue() {
      const products = this.field('products');
      if (products.isSet && this.operator === '$set') {
        return products.value.map(product => ({
          price: Products.findOne(product).price,
          quantity: product.quantity
        })).reduce((memo, current) => {
          return memo + (current.price * current.quantity);
        }, 0);
      }
    }
  }
}))

#4

ahhhhhhhh ok man thank you very very much!!


#5

No matter how I configure the schema, with blackbox or not I always get the following errors:

SimpleSchema.clean: filtered out value that would have affected key "orders", which is not allowed by the schema
simple-schema.js:737 SimpleSchema.clean: filtered out value that would have affected key "orders.$", which is not allowed by the schema
collection2.js:374 Uncaught Error: After filtering out keys not in the schema, your object is now empty

I really cannot get it, I’ve read alot of other meteor applications sources and it seems they all use the type and object configuration as below:

@purchaseOrders = new Meteor.Collection('purchaseOrders');

Schemas.purchaseOrders = new SimpleSchema
  message:
    type: String
    label: "Extra message or instructions"
    optional: true
    autoform:
      afFieldInput:
        type: "textarea"
        rows: 4

	purchaseStatus:
		type: String
    optional: true

	orders:
		type: Object
    optional: true

  "orders.$":
    type: Object

  "orders.$.productId":
    type: String

  "orders.$.quantity":
    type: Number
    min: 1

  "orders.$.title":
    type: String

  "orders.$.supplierEmail":
    type: String

  "orders.$.owner":
    type: String

No matter how I try to configure this collection I cannot seem to insert to it, very strange indeed.

Any ideas why I cannot save to the collection and get these errors? I also am using a before hook to set the variable

AutoForm.hooks
	confirmPurchaseOrder:
		before:	insert: (doc,template) ->
			doc.orders = Orders.find({}).fetch()
			console.log doc.orders
			return doc
		onSubmit: (insertDoc, updateDoc, currentDoc) ->
			console.log 'purchase form submitted'
		onError: (name, error, template) ->
  		console.log name + ' error:', error

In the console I can see the doc.orders is set to the document returned. But I cannot save it.


#6

I thought it was maybe this error (https://github.com/aldeed/meteor-autoform/issues/663) so I tried using the JSON.stringify but I still get the same error from SimpleSchema.clean


#7

Are you using a quickform or an autoform? And if it is an autoform, can you paste in your form code please.


#8

@serkandurusoy sure, I’m doing this inside a modal

<div class="modal-body">
                    <p>

                      <ul class="list-group">

                        {{#each orders}}
                    		  {{> orderItem}}
                    		{{/each}}

                      </ul>

                       {{#autoForm collection="PurchaseOrders" type="insert" id="confirmPurchaseOrder"}}
{{> afQuickField name="orders" type="hidden" value=orders}}
                          {{> afQuickField name="message" rows=4 type="textarea" style="width: 100%;"}}
                          <button type="submit" class="btn btn-success" id="confirmOrderFinal">Confirm Order</button>
                       {{/autoForm}}

										</p>

                </div>`

#9

@tomtom87 the problem here is, your schema expects the orders array to be filled within the form itself but since it is hidden, it is not validated.

You can either prefill the values on form creation with autoValue or, create a single “orderMessage” schema that takes the message input only and attaches the order details later on, passing them on to the target collection.


#10

@serkandurusoy ok I think I got it, by any chance to you have a example of populating the autoValue with content inside of the autoForm context like we have it here.

I couldn’t figure out how to get that working before inside the schema.


#11

you provide a doc attribute to the autoform containing the initial values of your fields

<AutoForm doc=orders ....../>

such that orders is a helper on the containing template and returns Orders.find({}).fetch()


#12

ahh ok I will try this and get back to you