Store and parse array in model in Waterline - arrays

Using the newest version of Waterline 0.13.1-6 standalone.
The array type no longer exist in this version. So I assume the way to store arrays is now to use the JSON type.
Sample of my model Model:
attributes: {
someArray: { type: 'json' }
}
Problem: on an instance of Model, model.someArray is now a String. I should JSON.parse it each time I request one to get the values in the array. That's very not convenient and can obviously lead to errors.
Is there a built-in way in the new Waterline to make this clean (automatically parse JSON fields...)?

You are fine to use JSON as you are suggesting. No need to parse it, this is done automatically when you do your meta fetch or find. You can do
YourModel.create({someArray: [1,2,3]}).meta({fetch: true}).then( out => {
console.log(out.someArray[0]); //1;
});
I would have some other identifying attribute for finding it, like say myRef: {type: 'string'}
Then you can do
YourModel.find({myRef: 'something'}).limit(1).then( out => {
console.log(out[0].someArray[1]); //2
});

Related

When should I use _id in MongoDB?

MongoDB has a field for every document called "_id". I see people using it everywhere as a primary key, and using it in queries to find documents by the _id.
This field defaults to using an ObjectId which is auto-generated, an example is:
db.tasks.findOne()
{
_id: ObjectID("ADF9"),
description: "Write lesson plan",
due_date: ISODate("2014-04-01"),
owner: ObjectID("AAF1") // Reference to another document
}
But in JavaScript, the underscore behind a field in an object is a convention for private, and as MongoDB uses JSON (specifically, BSON), should I be using these _ids for querying, finding and describing relationships between documents? it doesn't seem right.
I saw that MongoDB has a way to generate UUID https://docs.mongodb.com/manual/reference/method/UUID
Should I forget that _id property, and create my own indexed id property with an UUID?
Use UUIDs for user-generated content, e.g. to name image uploads. UUIDs can be exposed to the user in an URL or when the user inspects an image on the client-side. For everything that is on the server/not exposed to the user, there is no need to generate a UUID, and using the auto-generated _id is preferred.
An simple example of using UUID would be:
const uuid = require('uuid');
exports.nameFile= async (req, res, next) => {
req.body.photo = `${uuid.v4()}.${extension}`;
next();
};
How MongoDB names its things should not interfere in how you name your things. If data sent by third-party hurts the conventions you agreed to follow, you have to transform that data into the format you want as soon as it arrives in your application.
An example based in your case:
function findTaskById(id) {
var result = db.tasks.findOne({"_id": id});
var task = {
id: result._id,
description: result.description,
something: result.something
};
return task;
}
This way you isolate the use of Mongo's _id into the layer of your application that is responsible to interact with the database. In all other places you need task, you can use task.id.

map big json object to model object in typescript

I have array of object, each object contains;
{
Id:"..",
name:"..",
foo1:"..",
foo2:"..",
...
}
I need only 2 properties of these items so I have created an interface;
export interface IMenuModel{
Id:number;
name?:string;
}
and retrieve data within this method below:
fetch(`..`).then((response: Response): Promise<{ value:IMenuModel[] }> => {
return response.json();
})
.then((response: { value: IMenuModel[] }): void => {
debugger //expected response is array of IMenuModel but it still contains all properties
I expect this response object as array of my custom model(IMenuModel) but it still contains all properties retrieved from remote source.
I can pluck them with ".map()" function thats ok but there is return type defined to function(response: { value: IMenuModel[] }) so I shouldnt have to do this(or do I have to map it manually each time).
Why still response not in my object model and whats the most efficient way to achieve this?
TypeScript is mostly a type layer on top of JavaScript. These typings do not change the typed object. When transpiled into JavaScript the typings are simply dropped. If you apply an interface (or multiple interfaces) to your JSON object, you don't change the nature of the object, you just declare the guarantees of that interface.
So when you define your IMenuModel interface and apply it to your imported object you are saying: "I know and I can guarantee that the given object provides the members defined in the interface." This guarantee is satisfied by your object, so everything is fine there. The object however is still transmitted and restored in its full glory. Consider the interfaces as minimum guarantees, not as full descriptions of the object.
If you don't want the additional members of the object, your only choice is to let the server send only the parts of the object you need. If you can't do that, you don't need to worry, as your object meets the minimum requirements of the interface. Just ignore the additional values.

How do we compare the value in RealmSwift List and Json nested Array?

Realmswift Data Model
class User {
let id = RealmOptional<Int>()
dynamic var name = ""
let albums = List<Album>()
override static func primaryKey() -> String {
return "id"
}
}
class Album: Object {
dynamic albumName = ""
let imageIDs = List<ImageID>()
}
class ImageID: Object {
let imageId = RealmOptional<Int>()
}
JSON data
{
"10001": {
"id" : 10001,
"name": "John",
"album": {
"albums": [
{
"albumName": "Summer1999",
"imageIds": [11223, 11224, 11227]
},
{
"albumName": "Xmas1999",
"imageIds": [22991, 22997]
},
{
"albumName": "NewYear2000",
"imageIds": [5556, 776, 83224, 87543]
}
]
}
}
}
I have the above json data and I m using SwiftyJSON to parse the data then write into realm. Everything is working great except for checking and updating of data (for example imageIds on json file have changed).
Question: How do i compare the JSON arrays and RealmSwift List to determine it any updates need to be written into the database?
You can take advantage of your primary key here. As Realm Swift documentation states:
Creating and Updating Objects With Primary Keys: If your model class
includes a primary key, you can have Realm intelligently update or add
objects based off of their primary key values using
Realm().add(_:update:).
So (I assume that you get the JSON from some kind of a request (REST etc.) and then parse it with SwiftyJSON to create a 'User' object) you can treat the new 'User' object as regular new 'User' and try to add it to Realm as usual, but 'update' parameter must be 'true'. If there already was a user with the id of the 'User' object you are trying to add, it will just update the existing 'User' i.e. changing its modified values from the new 'User' created by parsing new JSON data. This might look something like this:
//Parse JSON and create a 'User'
let newUserFromJSON = parseAndCreateUserFromJSON(JSONData)
let realm = try! Realm()
do {
try realm.write {
realm.add(newUserFromJSON, update: true)
}
} catch let error as NSError {
print("error writing to realm: \(error.description) & \(error)")
} catch {
print("error writing to realm: UNKNOWN ERROR")
}
I'm afraid there's probably no easy answer to this. There's no mechanism in Realm to compare the contents of a Realm Object to an external object to see if their data matches. You would need to iterate through each object in the Realm object and manually compare it.
This wouldn't be too much code to write (Since you can get a list of all of the Realm file's properties via the objectSchema property of Realm objects, and then use key-value coding to pull them out in a single for loop), but would still be a fair amount of overhead to perform the compare.
That being said, if what you're wanting to look at is just certain properties that might change (i.e. like you said, just the imageIDs property), then you could easily just check the values you need.
What bcamur has suggested is definitely the quickest (And usually preferred for JSON handing) solution here. As long as you've set your primary key properly, you can call Realm.add(_:, update:) with update set to true to update the object.
Please keep in mind this doesn't merge the new data with what was already in Realm; it'll completely overwrite the old object with the new values, which if it sounds like your ID numbers are changing, would be the best course of action.

Backbone Collection get property

Got a server returning a JSON object like so:
{
'key1':'value'
'key2':{
'key2_0':'value'
}
}
And a collection:
var Collection = Backbone.Collection.extend({
url:api.url//which returns the object above
});
var collection = new Collection();
collection.fetch({
success:function(data){
//do something
}
});
Now i need to use certain properties of the collection throughout my application, but say i need key1, i always have to do collection.at(0).get('key1');//returns 'value', because the data returned is stored within the collection, in a new Array at key 0.
Question:
How to directly... collection.get('key1')//now returns undefined... because it is.
I know i could expose an object to the global scope in the collection success function some_other_var = data.toJSON()[0] and access the some_other_var properties directly, but that's not what i'm looking for;
In order to use the get() function from a Backbone.Collection you need to know the model id or cid wanted.
For instance, lets say your data coming from the server is like follow:
[{
id: '123',
name: 'Alex'
}, {
id: '456',
name: 'Jhon'
}]
In that case you can do this:
this.collection.get('123').get('name') // Return "Alex"
Keep in mind that collection is just a set of model, so behind the scenes by doing collection.get() you are getting a model
Tip: If you don't have any kind of id in your server data, there is always the option of using underscore methods:
find
filter
some
contains
etc
It seems like you're trying to ascribe attributes to a collection, but a collection is merely a set of models. Having additional data that is constant throughout the collection suggests that it should be wrapped inside another Model, which is demonstrated here: Persisting & loading metadata in a backbone.js collection

Map JSON Object to Model/Store

I'm using Worklight framework to construct a mobile app for IOS, and is using Sencha Touch 2.3 to build the app.
Due to the environment, i cannot use proxy in Sencha Touch Store/Model objects to load data from the server, as i would need to use Worklight's adapter to retrieve the info. I have managed to do that using some boilerplate codes.
However, i wish that i could utilize the Sencha Model more, and as such, am thinking whether it is possible for me to load a JSON object into the Model object automatically, without specifying a proxy.
Currently i'm doing a lot of loop and setter call to load the data from the JSON object to a model, like below:
var profile = Ext.create('Profile', {
Id: rawProfile.Id,
Name: rawProfile.Name
Age: rawProfile.Age
.....
}
where rawProfile is the JSON object i loaded from the server.
Any way i can make this cleaner?
You could create a Model class which would contain the data contained in your rawProfile object.
Ext.define('MyModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'Id',
name: 'Age',
...
}],
proxy: {
type: 'memory',
reader: 'json'
}
});
I've also set an in memory proxy which will read json objects.
You could then create a Store which would use the model you defined and the in memory proxy (meaning you wouldn't be using Ext's build in ajax messaging).
Ext.create('MyStore', {
model: 'MyModel',
autoLoad: false
});
Setting the autoLoad to be false, as you want to get the data from a different source.
Therefore, once you have your json object you can load it into the store by calling store.loadRawData(jsonObject).
In this case, the jsonObject would be the object containing all the json objects returned from the server, meaning that your code doesn't have to handle iterating through the records and you can leave it to the Sencha classes.
However you would need to figure out the writing data back to the server.
I'd recommend running through the Sencha Data Package tutorial as it gives a good intro to the data package
If all the fields map 1:1 with the json object, you can do this:
var profile = Ext.create('Profile', rawProfile);
Alternatively (or to avoid the convert functions for fields to be called), you can directly set the data property on the created model.
var profile = Ext.create('Profile');
profile.data = rawProfile;
Again, this requires a 1:1 on the fields and json object.

Resources