Meteor update a Collection object - meteor

in Meteor, I'm having a collection with a Schema, and a number of items are added dynamically.
In this case, I'm dealing with milestones object, and once the user check one off I want to update complete in this Collections item to true (default is false)
Here is my schema
milestones: {
type: Array,
optional: true
},
'milestones.$': {
type: Object
},
'milestones.$.name': {
type: String
},
'milestones.$.hours': {
type: Number
},
'milestones.$.complete': {
type: Boolean
}
How do I write a $set statement for this?

You have an array of objects so, $elemMatch do the trick here.
Projects.update({_id:this._id},{milestones:{$elemMatch:{'milestones.$‌​.name':this.name}},{$set:{'milestone.$.complete':value}}})

So thanks to Aldeed I found a solution - which needs to be called on server side, otherwise it won't let the update happen. Do:
Projects.update({_id:currentPostId, 'milestones.name':name}, {$set:{'milestones.$.complete':true}});
The function is called on the client with Meteor.call with all needed params.

According to your schema you have an object containing an array of objects. So you should write you $set like this:
{$set: {'milestone.$.complete':value}}
This will update the first array element corresponding to the query.
You can find here the official documentation if you want to know more about arrays updates in Mongo.

Related

Deleting all files in a firebase folder?

The Firebase documentation on deleting data says:
Delete data
The simplest way to delete data is to call remove() on a reference to the location of that data.
You can also delete by specifying null as the value for another write operation such as set() or update(). You can use this technique with update() to delete multiple children in a single API call.
can anybody explain to me what they mean by the last line I think is could help me delete all files in a firebase folder?
In Firebase:
dataRef.remove() is strictly equivalent to dataRef.set(null)
dataRef.child('foo').remove() is strictly equivalent to dataRef.update({ foo: null })
That means that setting or updating to null will effectively remove the property.
Updates can be used for removing multiple properties in that way:
Consider this example Firebase Object:
exampleData = {
foo: 'anyValue',
bar: 'otherValue',
baz: {
aProp: true,
anotherProp: false
}
}
The following
db.ref('/exampleData').update( { bar: null, 'baz/aProp': null })
will result in the following object:
exampleData = {
foo: 'anyValue',
baz: {
anotherProp: false
}
}
So you can use one update instead of multiple remove (or set) to delete several properties.
If you have this in your database:
users: {
user9266622: {
id: 9266622,
name: "SylvainC"
},
user209103: {
id: 209103,
name: "Frank van Puffelen"
}
}
Then you can delete a specific property with something like:
firebase.database().ref("/users/user209103/name").remove();
You can remove an entire branch by calling remove() on the top of that branch. So to remove "my" entire profile:
firebase.database().ref("/users/user209103").remove();
I think this last snippet is what you're looking for: it removes /users/user209103 and everything under it.
The last line of the documentation you quote is about updating/removing multiple branches/properties in distinct locations in one call. For example, say you want to remove the id property from both profiles (since they're redundant). You can do this with:
firebase.database().ref().update({
"/users/user9266622/id": null,
"/users/user209103/id": null
});
This is called a multi-location update, since you're updating two locations by their full path.

validating custom object in Meteor Simpleschema

I am trying to validate an object using SimpleSchema in Meteor, before inserting it into the database.
The object looks like this, as I print it from the Meteor method that calls the insert:
channels: { '1': [ 'rect4557-6-4-5-7-4-2', 'rect4557-6-4-97-0-7-6-3' ] } }
If I insert it in the database without attaching a schema to it, it works fine. However, when I have it run through SimpleSchema, the field value as outputted from console.log in the custom validation method is an empty object {}. Even if I don't run any validation, an empty object is stored if SimpleSchema is used.
Code to produce the simpleschema value output:
Arch.schema = new SimpleSchema({
channels: {
type: Object,
custom: function validateChannels() {
console.log("this.value:", this.value)
}
});
Architectures.attachSchema(Architectures.schema);
Really, what should I do? Is this a bug in SimpleSchema?
It looks like you just need to add blackbox: true option. SimpleSchema does not support arbitrary object keys unless you mark it as a blackbox object. See https://github.com/aldeed/meteor-simple-schema#blackbox
The filtering, which is part of the automatic cleaning, is what strips this out for you. If you want to prevent that in a specific insert call, just pass filter: false option. See https://github.com/aldeed/meteor-collection2#skip-removing-properties-that-are-not-in-the-schema

Separate form validation with Meteor

I'm using collection2 and I'm trying to get it to handle validation is a specific way. I have a profile schema which looks kind of like this:
Schema.UserProfile = new SimpleSchema({
name: {
type: String,
optional: false
}
location: {
type: String,
optional: true
}
gender: {
type: String,
optional: false
}
});
Schema.User = new SimpleSchema({
username: {
type: String,
optional: true
},
emails: {
type: Array,
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
services: {
type: Object,
optional: true,
blackbox: true
},
roles: {
type: [String],
optional: true
},
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Now, on my registration form I'm requiring the user to select their gender and then later once they log in, users are presented with a separate form asking for their name and location. Here's the problem:
The registration form works and everything goes through with saving. When they try to save the internal form with location and name though I get an error:
Error invoking Method 'updateProfile': Gender is required [400]
I know it's happening because it's required in the schema but I've already obtained this information. How do I not require that? Or do I set up validation per form?
You have to add validation through jquery or you can use toaster for display the error on client side.
Read this also : link
I assume you use aldeed:autoform for your forms. When you use normal type in the form, all fields, even those already filled marked as mandatory have to be submitted. Two ways to fix this:
Dirty way: set hidden field with the prefilled value.
You can also set your form type as update as seen in the doc. This way, simple-schema will validate your newDoc already filled with your previous entries without screaming.
The solution number two is the one I use in most cases. This plus autoform's hooks give you enough flexibility to adapt to most use-cases you might encounter.
I don't know whether or not it is a more elegant solution, but we've stopped attaching simpleSchemas to documents in our current project.
We instead have different schemas in each collection's namespace, one for checking user input on insert, one on update, and and one to be used to fill defaultValue when inserting a new doc (which can be done either by the client or the server, in which case we don't check for input). We call .validate() or .clean() depending on what we want to do.
With clever use of the possibility to build schemas from array of schemas, we're not writing bigger schemas in the end (there's more of them though), but we have total control on when we check, and which fields are checked.
From the SimpleSchema docs:
Say you have a required key "friends.address.city" but
"friends.address" is optional. If "friends.address" is set in the
object you're validating, but "friends.address.city" is not, there is
a validation error. However, if "friends.address" is not set, then
there is no validation error for "friends.address.city" because the
object it belongs to is not present.
So the error happens because you're including profile on both forms and gender is not optional within profile. I can think of two ways to solve this:
Have additional objects under profile that are both optional and contain required fields for name/location on one (though it seems like location might be optional in both scenarios based on your code) and a required field for gender on the other. I don't particularly like this solution but it prevents needing form validation.
Use jQuery form validation (I use the package themeteorchef:jquery-validation) and make all your fields in profile optional.
It also looks like SimpleSchema accepts a function for the optional property, so you could use some custom logic there - maybe you get arguments or a context in that function that will allow you to do what you want?
Hope that helps!

Datatype validation error - MeteorJS/Autoform/SimpleSchema/Embedded Simple Schema

I am using Simple Schema,collection hooks and Autoform packages in Meteor and I am trying to update a Embedded object in my schema in the after update collection hook. I feel I might doing something silly, but was just unable to solve this problem. I am getting the exeption while saving: Exception while invoking method '/providers/update' Error: 0 must be an integer
My schema:
Schemas.Providers = new SimpleSchema({
email: {
type: String,
label: 'Email Address',
autoValue: function() {
if (this.isInsert || this.isUpdate) {
return Meteor.user().emails[0].address;
}
},
autoform: {
afFieldInput: {
type: 'email'
}
}
},
officelocation: {
type: String,
label: 'Location of Office',
optional:true
},
location: {
type: [LocationSchema],
optional:true
}});
The collection hook that works:
Providers.after.update(function (userId, doc) {
var oldDoc = this.previous;
Providers.direct.update({_id: doc._id},{$set: {location:{
type:'Point',
coordinates:[0,0]
}}});
});
The collection hook that does not work.. Ideally I should not be updating after the collection update, but wanted to make sure this works:
Providers.after.update(function (userId, doc) {
var oldDoc = this.previous;
var array=[];
var iArray=doc.officelocation.split(",");
array.push(Number(iArray[1]));
array.push(Number(iArray[0]))
Providers.direct.update({_id: doc._id},{$set: {location:[{
type:'Point',
coordinates:array
}]}});
});
Looking at what you are trying to store, use parseInt instead of Number that you are using. It will return an integer that mongo can store.
The issue is not with the method that you are using. It is with the way you are storing data in mongo. Show us how your LocationSchema looks like.
Detail:
Mongo uses a different number format that what javascript uses. In javascript, a Number can be an integer, a float, a decimal or anything that you want. Mongo has very strict demands when it comes to integer or floats.
Overall, what it means is that if you want to store an accurate decimal number in mongo (which I suspect what you are trying to do), you have to either store it as a string (you loose the ability to do direct mongo operation such as $inc $gt etc) or divide it into two parts and store separably. The third option is to store it as a float which isn't accurate an is only useful if you want some kind of approximate value.

Meteor Collection - How to mark a property as unique

How can I mark a property in a Meteor Collection as unique? I am trying to create a document collection with each document having a name that is unique, and I can't figure out how to make this unique.
You know that mongo assigns a unique, non-human based _id to every document, and that often the title a user decides to call something doesn't need to be unique. That being said,
http://docs.mongodb.org/manual/tutorial/create-a-unique-index/ tells you how to make an index that forces a field to be unique:
db.collection.ensureIndex( { a: 1 }, { unique: true } );
You can run that from the mongo shell. It can also be called from the server js only. If you've created a collection by
Diaries = new Meteor.collection();
then just after adding the collection, in server code, you could add
Diaries.ensureIndex({ title: 1},{ unique: true });

Resources