Meteor update array of objects - meteor

I'm using Schema with this Meteor project. I've got an array of objects in the Schema, which I create them this way:
'milestones.$.name'
I create some properties like this, and allow for dynamic insert.
Now, I want to grab a milestone by name from milestones array and update some of its properties.
How can I do this?
I'm trying this at the moment, but still no positive result:
Projects.update(
{_id: currentPostId, 'milestones.name':this.name},
{$set: {'milestones.$': {name: this.name, hours: this.hours, complete:true}}}
);

Related

Vue-Firebase: Updating children & writing to child

I started working with Firebase and Vue also with VueFire and i dont understand how to update child nodes at Firebase.
I opened a firebase project and connected to it and i can push data to it.
Firebase
I made a vue component
import db from '../FireBase'
let team = db.ref('Teams');//Reference to Teams at firebase
let miss = db.ref().child('Teams'); //Attempt to get to the children of Teams
export default {
name: "App",
firebase: {
Teams_loc: db.ref('Teams'),
Mission: this.Teams_loc.child('Teams'),
missionKey: db.ref().child('Teams').push("").key,
},
...
I manage to get the Teams from firebase and send data to it:
this.$firebaseRefs.Teams_loc.push({
"test": "tester"
});
Which works but when i try to update the children inside
this.miss.push({
"where": "am i"
})
I get the following error
Cannot read property 'child' of undefined
And when i try to update a child
this.$firebaseRefs.missionKey.update(arr[0]);//arr[0] is an object
I tried looking at quite a few places but nothing seems to do the trick.
Thanks,
When you do the following you are doing an error at the second line.
Teams_loc: db.ref('Teams'),
Mission: this.Teams_loc.child('Teams'),
There is no child of the Teams node that has a key with the value `Teams.
So if you want to update an item, you first have to get its key (e.g. -LEzOBT-mp.....) and do as follows, as explained in the doc:
updateItem: function (item) {
// create a copy of the item
const copy = {...item}
// remove the .key attribute
delete copy['.key']
//possibly update (or add) some values of (to) the item
this.$firebaseRefs.Teams_loc.child(item['.key']).set(copy)
}
Also (if I am not mistaking) doing db.ref() will generate an error because you have to pass a value to ref().
I suggest that you study a bit more the doc and the example: https://github.com/vuejs/vuefire and https://github.com/vuejs/vuefire/blob/master/examples/todo-app/index.html
Update following your comment. Details on how to "know the random generated key"
According to the documentation:
Each record in the bound array will contain a .key property which
specifies the key where the record is stored. So if you have data at
/Teams/-LEzOBT-mp...../, the record for that data will have a .key of
"-LEzOBT-mp.....".
Look at this part of the doc: https://github.com/vuejs/vuefire#array-bindings.
So with this you will get all the keys of the Teams object. You have now to choose the item you want to update.
You could also declare a query in your firebase object, like:
firebase: {
team21483: this.database
.ref('Teams')
.orderByChild('teamCode')
.equalTo('21483')
}
and you would get an array with only one team, the one with TeamCode = 21483.
The best approach, in this latest case, is to manually bind to this Firebase query with the $bindAsArray (or possibly the $bindAsObject) instance methods, using a variable that you pass to equalTo().

How can I use two collections in one reactive table? Meteor Js

I wanna use two collections in one reactive table using meteorjs. I have two collections and I want to merge these collection in single table. I have no clues please help!!!
Take a look on reywood:publish-composite package. It allows you to publish reactive joins.
https://github.com/englue/meteor-publish-composite
When using reactive-table you can use a dynamic column which allows you to define a function for a column. You can then use this function to lookup data in another collection.
Example:
{ fieldId: 'someOtherThing', // needs to be unique in your table
key: 'otherId', // this should be the _id of the other collection you want to "join"
label: 'Some Label',
fn: function(_id){
const otherObject = OtherCollection.findOne(_id);
if ( otherObject ) return otherObject.someKey;
}
},

Simple Schema Meteor - Array Validation

I am using this package to validate data before going into a database collection. One field in my collection must contain an array of strings - how can I validate this?
YourCollection.attachSchema(new SimpleSchema({
...
yourArray: {type: [String]},
});

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 });

Get Meteor collection by name

Suppose I write:
new Meteor.Collection("foos");
new Meteor.Collection("bars");
Is there an API for accessing those collections by name? Something like Meteor.Collection.get(name), where name is "foos" or "bars"? I know I could write something like
var MyCollections = {
foos: new Meteor.Collection("foos");
bars: new Meteor.Collection("bars");
}
and then use MyCollections[name], but I'd prefer to use an existing API if one exists.
Based on Shane Donelley's mongoinspector
https://github.com/shanedonnelly1/mongoinspector
getCollection = function (string) {
for (var globalObject in window) {
if (window[globalObject] instanceof Meteor.Collection) {
if (globalObject === string) {
return (window[globalObject]);
break;
};
}
}
return undefined; // if none of the collections match
};
I've just found that package : https://github.com/dburles/mongo-collection-instances/
It allow you to
Foo1 = new Mongo.Collection('foo'); // local
Foo2 = new Mongo.Collection('foo', { connection: connection });
Mongo.Collection.get('foo') // returns instance of Foo1
Mongo.Collection.get('foo', { connection: connection });
// returns instance of Foo2
Hope it will help
This feature was added to Meteor in Feb 2016: "Provide a way to access collections from stores on the client"
It works like this:
Meteor.connection._stores['tasks']._getCollection();
And I was using it as follows to test inserts using the javascript console:
Meteor.connection._stores['tasks']._getCollection().insert({text:'test'});
For the insert it required the insecure package to still be installed otherwise got an access denied message.
As far as I can see in the collection.js source there currently is no way in the api to get an existing Collection by name, once it has already been initialized on the server. It probably wouldn't be hard to add that feature.
So, why not fork Meteor and submit a patch or create a smart package and share it I'm sure there are others out there who'd like the same feature.
With https://github.com/dburles/mongo-collection-instances you can use Mongo.Collection.get('collectionname')
Note that the parameter you're inserting is the same one you use when creating the collection. So if you're using const Products = new Mongo.Collection('products') then you should use get('products') (lowercase).
Note that they have a return value, so you can just do
var Patterns = new Meteor.Collection("patterns");
and use Patterns everywhere.
And when you need to subscribe to server updates, provide "patterns" to Meteor.subscribe().
If you have the same code for multiple collections, the chance is high that you're doing something wrong from a software engineering viewpoint; why not use a single collection with a type field (or something else that differentiates the documents) and use that instead of using multiple collections?
Rather than looking, I've just been doing:
Foos = new Meteor.Collection("foos");
or possibly put it inside another object. I haven't really been making a Collections collection object.
It seems there is no way to get at the wrapped Meteor.Collection object without saving it at creation time, as others have mentioned.
But there is at least a way to list all created collections, and actually access the corresponding Mongo LocalCollection object. They are available from any Meteor Collection object, so to keep it generalistic you can create a dummy collection just for this. Use a method as such (CoffeeScript):
dummy = new Meteor.Collection 'dummy'
getCollection = (name) ->
dummy._driver.collections[name]
These objects do have all the find, findOne, update et al methods, and even some that Meteor doesn't seem to expose, like pauseObservers and resumeObservers which seem interesting. But I haven't tried fiddling with this mongo LocalCollection reference directly to knowif it will update the server collection accordingly.
var bars = new Meteor.Collection("foos");
Judging by what the collection.js does, the line we use to instantiate the collection object opens a connection to the database and looks for the collection matching the name we give. So in this case a connection is made and the collection 'foos' is bound to the Meteor.Collection object 'bars'. See collection.js AND remote_collection_driver.js within the mongo-livedata package.
As is the way with MongoDB, whilst you can, you don't have to explicitly create collections. As stated in the MongoDB documentation:
A collection is created when the first document is inserted.
So, I think what you're after is what you already have - unless I've totally misunderstood what you're intentions are.
You can always roll your own automatic collection getter.
Say you have a couple of collections called "Businesses" and "Clients". Put a reference each into some "collections" object and register a Handlebars helper to access those "collections" by collections["name"].
i.e. put something like this on the client-side main.js:
collections = collections || {};
collections.Businesses = Businesses;
collections.Clients = Clients;
Handlebars.registerHelper("getCollection", function(coll) {
return collections[coll].find();
});
Then in your HTML, just refer to the collection by name:
{{#each getCollection 'Businesses'}}
<div> Business: {{_id}} </div>
{{/each}}
{{#each getCollection 'Clients'}}
<div> Client: {{_id}} </div>
{{/each}}
Look ma, no more generic "list all records" boilerplate js required!

Resources