Keep somewhere additional data after backbone's collection fetched - javascript

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.

Related

What's an elegant way to upload nested arrays with objects and other fields to Firestore? (Node.js, Javascript)

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.

data with function return vs. return plain data object

When I started with Vue.js I read about a case where you return a data property with return and sometimes without. I cannot find that article anymore that's why I'm asking here.
That's how I use it today
data: function () {
return {
myData : "data"
}
},
But that's how I see it in documentation very often - don't know the difference anymore:
data: {
myData: "data"
},
https://vuejs.org/2016/02/06/common-gotchas/#Why-does-data-need-to-be-a-function
Why does data need to be a function?
In the basic examples, we declare the data directly as a plain object. This is because we are creating only a single instance with new Vue(). However, when defining a component, data must be declared as a function that returns the initial data object. Why? Because there will be many instances created using the same definition. If we still use a plain object for data, that same object will be shared by reference across all instance created! By providing a data function, every time a new instance is created, we can simply call it to return a fresh copy of the initial data.

Returning MongoDB Items in Meteor

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?

Overriding backbone's parse function

I'm trying to use Backbone with an API.
The default API response format is:
{
somemetadatas:xxx ,
results:yyy
}
Whether it's a fetch for a single model or a collection.
So as far as I know I can override the Backbone parse function with:
parse: function (response) {
return response.results;
},
But I've seen in the documentation:
parse collection.parse(response)
parse is called by Backbone whenever
a collection's models are returned by the server, in fetch. The
function is passed the raw response object, and should return the
array of model attributes to be added to the collection. The default
implementation is a no-op, simply passing through the JSON response.
Override this if you need to work with a preexisting API, or better
namespace your responses. Note that afterwards, if your model class
already has a parse function, it will be run against each fetched
model.
So if I have a response for a collection fetch like that:
{
somemetadatas:xxx ,
results:[user1,user2]
}
The first parse function on the collection will extract [user1,user2].
But the doc says:
Note that afterwards, if your model class
already has a parse function, it will be run against each fetched
model.
So it will try to find response.results; on user1 and user2
I need both parse functions on the model and collection because both model and collection datas will be under the result attribute.
But if i fetch on a collection, I don't want the model parse function to be used againt a single array element.
So is there a solution to this problem?
I think of a solution where my collection parse function will transform something like this:
{
somemetadatas:xxx ,
results:[user1,user2]
}
into something like this:
[ {results.user1} , {results.user2} ]
So that the model parse function will not fail on a collection fetch.
But it's a bit hacky... is there any elegant solution to this problem?
By the way, as my API will always produce results of this form, is it possible to override by default the parse function of all my models and collections? (Sorry i'm a JS noob...)
You could test if the data you receive is wrapped by a results member and react accordingly. For example,
var M = Backbone.Model.extend({
parse: function (data) {
if (_.isObject(data.results)) {
return data.results;
} else {
return data;
}
}
});
And a Fiddle http://jsfiddle.net/9rCH3/
If you want to generalize this behavior, either derive all your model classes from this base class or modify Backbone's prototype to provide this function :
Backbone.Model.prototype.parse = function (data) {
if (_.isObject(data.results)) {
return data.results;
} else {
return data;
}
};
http://jsfiddle.net/9rCH3/1/
Parse also must be implemented in the Collection.
var EgCollection = Backbone.Collection.extend({
parse: function (data) {
if (_.isObject(data.results)) {
return data.results;
} else {
return data;
}
}
});
http://backbonejs.org/#Collection-parse

Cannot create Ember object from JSON

I have a problem with creating Ember objects from a JSON ajax data source. If I create the object the manual way, it works perfectly, and the view gets updated. If the data itself comes from a JSON ajax data call, however, it does not work. If I inspect the resulting objects, the Ember model objects does not get the correct getter and setter properties. Does anyone know why this happens?
App.AlbumView = Ember.View.extend({
templateName:'album',
albums:[],
getAll:function() {
var self = this;
//This works!
self.albums.push(App.Album.create({title: 'test', artist: 'test'}));
$.post('/Rest/list/album',null,function(data) {
$.each(data, function (index, item) {
//This does not work?!?
self.albums.push(App.Album.create(item));
});
}, 'json');
}
});
You should always use embers get('variableName') and set('variableName', newValue) methods when accessing instance variables of a view. Strange things tend to happen if you don't.

Categories

Resources