I'm trying to understand how Meteor returns database records. I'm running the following code:
Template.body.helpers({
items(){
return Items.find({});
},
json(){
console.log(this.items());
},
loggedIn(){
return Meteor.userId();
}
});
I'm a little confused as to why this json method doesn't just output and array, or more specifically why the child values don't really seem to just return an array of values.
I can get the values inline html using spacebars, but I'm not sure how to access those values through js. What simple thing am I missing here?
Collection.find() in Meteor returns a cursor, which is a function that can be used by Blaze templates (for example).
Collection.find().fetch() returns an array of objects (i.e. documents).
If you want to parse the database record between multiple helpers or even between templates and routes, why don't you use session variables.
For your example:
Template.body.helpers({
items(){
const items = Items.find({});
Session.set('itemArray', items);
return items;
},
json(){
console.log(Session.get('itemArray');
},
loggedIn(){
return Meteor.userId();
}
});
Does this work for you?
Related
This Meteor client code needs to group documents from a mongo collection by a field 'category' and return a sorted array of the unique values of the field 'category'. I am using Blaze template helper which returns an array populated by a collection.find.foreach since I could not find easy to follow examples on how to aggregate mongo collection of the client, How can I get the helper to wait till the collection operation is ready? Thanks
'jobs': function(){
let categories = []
Jobs.find({}).forEach((doc) => {
if(!categories.includes(doc.category)) categories.push(doc.category)
})
return categories.sort()
}
Update: example added
collection Jobs has data like:
{'category':'Inspection','label':'Pink','discription':'R...}
{'category':'Inspection','label':'Blue','discription':'U...}
{'category':'Inspection','label':'AOR', 'discription':'A...}
{'category':'Inspection','label':'Prep','discription':'P...}
{'category':'Inspection','label':'Chec','discription':'I...}
{'category':'Inspection','label':'Diag','discription':'D...}
{'category':'Service','label':'basic','discription':'Cha...}
{'category':'Service','label':'regular','discription':'C...}
I need the unique values of the field category, which are (Inspection, Service).
update 2
On the mongo shell, the solution would be:
db.jobs.distinct( "category" ) which produces ["Inspection","Service"]
All of the given code does not require Mongo's aggregate function but can be solved with normal query functionality:
if(!categories.includes(doc.category)) can be solved using the $in operator and .sort() can be solved using the sort transform operation:
'jobs': function(){
return Jobs.find({ category: { $in: categories } }, { sort: { category: 1 } })
},
The returned value is a Mongo.Cursor which will trigger reactivity on changes.
Readings:
https://docs.mongodb.com/manual/tutorial/query-documents/
https://docs.meteor.com/api/collections.html#sortspecifiers
http://blazejs.org/api/templates.html#Template-helpers
I have data that I would like to deploy to a Firestore collection from a cloud function that runs on Node10.
The collection is called "activities" and should hold united arrays with objects and additional fields.
First of all, this is the most important array with objects:
listOfNonEmptyObjects = [
{ pronounsDefinite: 'I' },
{ verbsInfinitiv: 'work' },
{ prepositions: 'in' },
{ articles: 'the' },
{ nouns: 'garden' }
];
This is how I upload it, while the sessionID_original is basically the document name and the intentDisplayName is just a string to create the object inside arrayUnion:
return writeToDatabase (
sessionID_original,
{"activities" : admin.firestore.FieldValue.arrayUnion(createObject(intentDisplayName, listOfNonEmptyObjects))}
);
These are the functions for this:
function createObject(key, list){
var test = {};
test[key] = list;
return test;
}
function writeToDatabase(sessionID_original, data) {
const docRef = db.collection('users').doc(sessionID_original);
return db.runTransaction(t => {
return t.get(docRef)
.then(doc => {
t.set(docRef, data, {merge: true});
});
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
});
}
Now this is what it looks like when I look in Firestore:
Screenshot of collection with listOfNonEmptyObjects
But now I would like my functions to add a timestamp or additional information to the data:
Screenshot of collection with listOfNonEmptyObjects and timestamps and booleans and so on
When I try this it gives me an error that I can't write nested arrays.
But then how can I achieve this data structure. Or is my data structure a bad one?
Another attempt could be to just put a timestamp in the listOfNonEmptyObjects.
But I think this would make it more difficult to read the timestamps then.
So every time there is a new activity or something I would like the functions to add it to the activities collection with a timestamp and maybe other fields like booleans etc.
It is not clear to me that you are thinking about Firestore in the correct way.
Firestore is a Document Store Database. For the most part, you will read and write entire Documents (JSON objects or sets of key/value pairs) at at time. Though you can make nested and complicated data structures within a single document, there are limitations in terms of overall size and index capabilities that will ultimately restrict the usefulness of a single document being complex (see Firestore limits and quotas)
It sounds to me like the elements you are putting in your array might rather benefit from being their own documents?
There have been a few good threads on the subject of "Firestore arrays vs subcollections". This one seems to call out the pros/cons quite well.
I'm trying to load includes on an existing model in sequelize. In express we pre check the models to see if they exist in the middleware.
So once we're in the actual "controller" we want to run some includes on that existing model that is passed in.
req.models.item.incude([
{model: Post, as: 'posts'}
])
Is there any way to accomplish this?
EDIT:
I know we can do something like this.
return req.models.item.getThing()
.then(function (thing) {
req.models.item.thing = thing;
return req.models.item;
});
But:
My expansions for includes are a dynamic property that come via url parameters, so they are not know ahead of time.
It I return the above you will not see the "thing" in the response. I need it nicely built as part of the original instance.
Something like a .with('thing', 'other.thing'); notation would be nice. Or in the case of sequelize .with({include: ...}); or .include([{model: ...}]);
If the variable req.models.item is already an Instance but without its other related instances ("includes"), then you could include them using something like the following code:
Item.findAll({
where: req.models.item.where(),
include: [{
model: SomeAssociateModel,
}]
})
.then(function(itemWithAssoc) {
// itemWithAssoc is an Instance for the same DB record as item, but with its associations
});
See here for some documentation. See here for a script demo'ing this.
Update: Given the instance, how do I just get the associated models?
To do this just use the automatically generated "getAssociation" getter functions, e.g.:
function find_associations_of_instance(instance) {
return instance.getDetails();
}
I've updated the script to include this as an example. For more information on these functions, see the SequelizeJS docs.
I receive next data from server after get request:
{ data: { items: [...], itemsCount: Number } }
I'm saving items in backbone collection in next way:
parse: function (response) {
return response.data.items;
}
How do I keep somehow in collection or outer itemsCount?
If I understand your question correctly, the answer is straight forward. You're not limited to simply saving data in a collection or in the model.attributes hash. Backbone objects are traditional javascript objects and you can create any custom property you'd like.
So, in your parse function, you could do...
parse: function (response) {
this.itemsCount = response.itemsCount
return response.data.items
}
Note that I am assuming that your parse function is scoped to the collection. If it's not, then I need to see more code to demonstrate how to properly scope the function.
I'm developing HTML5 app with Knockout.js and JayData and I encountered a problem while implementing a pull-to-refresh data list.
I query a remote OData service with JayData API and assign the results to a KO observable array:
db.MySet
.orderBy('it.Field1')
.skip(recordsToSkip)
.take(20)
.toArray()
.then(function(result) {
self.MyDataList(result);
}
I always lose the old records. How could I fix my code?
I guess there is a small thing missing while bindig the result to the Knockout observable: check if the existing array already contains elements and append the result to the existing ones.
My colleague Viktor has a tutorial, which implements a highscore list with Knockout+JayData pull-to-refresh
db.MySet
.orderBy('it.Field1')
.skip(recordsToSkip)
.take(20)
.toArray()
.then(function(result) {
if (result.length){
if (self.MyDataList().length){
self.MyDataList(self.MyDataList().concat(result));
}else{
self.MyDataList(result);
}
}
});
Does this fix the app?
The full context of the example can be found on GitHub
You will need to concatenate your new array of objects to your old list:
.then(function(result) {
oldList = oldList.concat(result);
self.MyDataList(oldList);
}
(So, on the first run, you will need to set oldList = [])