Object Arrays in Azure Table Storage - arrays

I'm trying to build a simple Mobile Service on Azure and I'm having some problems while inserting my information. Right now, I've got two classes in my model, User and Car. A User has an AccountID, a Name (all these Strings) and an Array of Car. A Car has a Plate, a Color and a Model (all these Strings).
I'm serializing the User object correctly to JSON and when I try to do request.execute() it throws an error that says "The value of property 'cars' is of type object which is not supported". I know that only string, number, bool and date are suppported.
What I'd like to do, is to have two separate tables, one for users and another one for cars, and somehow establish a relationship between them. This is the script I've written so far
function insert(item, user, request) {
if(item.accountID !== user.userId){
request.respond(statusCodes.UNAUTHORIZED,
"Unauthorized user");
} else {
if(item.cars.length){
var tableCars = tables.getTable('cars');
populateTable(tableCars, request, item.cars);
}
request.execute();
}
}
function populateTable(table, request, array){
var index = 0;
var insertNext = function(){
if(index < array.length){
var toInsert = array[index];
table.insert(toInsert, {
success: function(){
index++;
insertNext();
}
});
}
};
insertNext();
}
At this point I've got several problems. If I leave it this way, it crashes because items.cars is an Array of Car (an object for JS) but I do want to have here some kind of id to find cars that belong to this User in its table. Maybe I should add some kind to 'owner' to Car, but I'm not sure, my knowledge of databases is somehow poor.
What should I do?

Azure table storage does not support relational tables. Furthermore, ATS does not support storing of strongly typed child objects as a part of parent entities. ATS is a key-value entity-based table storage. It only supports basic data types like string, date, double, boolean, etc.
If you want to store complex objects in ATS (complex, meaning objects that contain other objects), it is suggested that you should serialize the child objects as strings rather then objects, when storing the data and de-serialize the strings back into objects during retrieval.
Alternatively, you can get very fancy with your Row/PartitionKeys and store Parent object and child objects as different entities within the same PartitionKey - and when reading the values back, reconstruct the hierarchy.

Related

Get Firestore collection and sub-collection document data together

I have the following Firestore database structure in my Ionic 5 app.
Book(collection)
{bookID}(document with book fields)
Like (sub-collection)
{userID} (document name as user ID with fields)
Book collection has documentes and each document has a Like sub-collection. The document names of Like collection are user IDs who liked the book.
I am trying to do a query to get the latest books and at the same time trying to get the document from Like sub-collection to check if I have liked it.
async getBook(coll) {
snap = await this.afs.collection('Book').ref
.orderBy('createdDate', "desc")
.limit(10).get();
snap.docs.map(x => {
const data = x.data();
coll.push({
key: x.id,
data: data.data(),
like: this.getMyReaction(x.id)
});
}
async getMyReaction(key) {
const res = await this.afs.doc('Book/myUserID').ref.get();
if(res.exists) {
return res.data();
} else {
return 'notFound';
}
}
What I am doing here is calling the method getMyReaction() with each book ID and storing the promise in the like field. Later, I am reading the like value with async pipe in the HTML. This code is working perfectly but there is a little delay to get the like value as the promise is taking time to get resolved. Is there a solution to get sub-collection value at the same time I am getting the collection value?
Is there a solution to get sub-collection value at the same time I am getting the collection value?
Not without restructuring your data. Firestore queries can only consider documents in a single collection. The only exception to that is collection group queries, which lets you consider documents among all collections with the exact same name. What you're doing right now to "join" these two collections is probably about as effective as you'll get.
The only way you can turn this into a single query is by having another collection with the data pre-merged from the other two collections. This is actually kind of common on nosql databases, and is referred to as denormalization. But it's entirely up to you to decide if that's right for your use case.

Defining relationships and processing data within them

I have got myself a bit confused with relationships, I am not sure if I am splitting things up too much? I am dealing with a reporting system where there can be different types of reports. So, I have my standard reports table and model, and within the model, I define that a report can have one report type.
public function reportType() {
return $this->hasOne('App\ReportType');
}
Now a reportType can be one of three different Types, lets call them A, B and C. Each reportType collects different data. As such, within the ReportType model, I define a has one relationship with the type it has
public function reportTypeA() {
return $this->hasOne('App\ReportTypeA');
}
So the above states that a reportType can have one reportTypeA. I also have in this Model that it can have one reportTypeB and C. Now within reportTypeA model, I state that reportTypeA can have one set of reportTypeAData
public function reportTypeAData() {
return $this->hasOne('App\ReportTypeAData');
}
I have the inverse relationships in all Models. So essentially, I have
Report->ReportType->ReportTypeA->ReportTypeAData
ReportTypeB->ReportTypeBData
ReportTypeBData2
ReportTypeC->ReportTypeCData
Reason I have the data models is because some reports have more than one set of data. So the above shows that Report B has 2 sets of data, each with its own structure.
So the above works, but it seems very "waterfall" approach to me. I will clean this up at some point to hopefully make it more structured.
This is where I am confused though, with the above approach, how can I get the data for a Report? So in my controller, I have something like
$report = Report::where('user_id', Auth::user()->id)->first();
This will get me the first report for the logged in User. I can then get the report data doing something like this
$reportData = $report->reportType->reportTypeA->reportTypeAData->all()->toArray();
Which seems proper overkill having to go through all relationships. My main problem is this, I want to chunk the data back to the frontend, so I will have something like this
DB::table("report_type_a_data")->chunk(100, function ($data) use ($handle) {
foreach ($data as $row) {
// Add a new row with data
fputcsv($handle, [
$row->id,
$row->name
]);
}
});
Now obviously that will loop all data, where I only want the data for the report I am dealing with. Additionally, when I try this, I get an error
You must specify an orderBy clause when using this function
Why am I getting this? Any help with organising things better and how I can process a specific reports data is highly appreciated.
Thanks
You need orderBy() when you use chunk().
For example.
DB::table('users')->orderBy('id')->chunk(100, function ($users) {
foreach ($users as $user) {
//
}
});
or you can use chunkById().
DB::table('users')->where('active', false)
->chunkById(100, function ($users) {
foreach ($users as $user) {
//
}
});
Please refer to the document

AngularFire - How do I query denormalised data?

Ok Im starting out fresh with Firebase. I've read this: https://www.firebase.com/docs/data-structure.html and I've read this: https://www.firebase.com/blog/2013-04-12-denormalizing-is-normal.html
So I'm suitably confused as one seems to contradict the other. You can structure your data hierarchically, but if you want it to be scalable then don't. However that's not the actual problem.
I have the following structure (please correct me if this is wrong) for a blog engine:
"authors" : {
"-JHvwkE8jHuhevZYrj3O" : {
"userUid" : "simplelogin:7",
"email" : "myemail#domain.com"
}
},
"posts" : {
"-JHvwkJ3ZOZAnTenIQFy" : {
"state" : "draft",
"body" : "This is my first post",
"title" : "My first blog",
"authorId" : "-JHvwkE8jHuhevZYrj3O"
}
}
A list of authors and a list of posts. First of all I want to get the Author where the userUid equals my current user's uid. Then I want to get the posts where the authorId is the one provided to the query.
But I have no idea how to do this. Any help would be appreciated! I'm using AngularFire if that makes a difference.
Firebase is a NoSQL data store. It's a JSON hierarchy and does not have SQL queries in the traditional sense (these aren't really compatible with lightning-fast real-time ops; they tend to be slow and expensive). There are plans for some map reduce style functionality (merged views and tools to assist with this) but your primary weapon at present is proper data structure.
First of all, let's tackle the tree hierarchy vs denormalized data. Here's a few things you should denormalize:
lists you want to be able to iterate quickly (a list of user names without having to download every message that user ever wrote or all the other meta info about a user)
large data sets that you view portions of, such as a list of rooms/groups a user belongs to (you should be able to fetch the list of rooms for a given user without downloading all groups/rooms in the system, so put the index one place, the master room data somewhere else)
anything with more than 1,000 records (keep it lean for speed)
children under a path that contain 1..n (i.e. possibly infinite) records (example chat messages from the chat room meta data, that way you can fetch info about the chat room without grabbing all messages)
Here's a few things it may not make sense to denormalize:
data you always fetch en toto and never iterate (if you always use .child(...).on('value', ...) to fetch some record and you display everything in that record, never referring to the parent list, there's no reason to optimize for iterability)
lists shorter than a hundred or so records that you always as a whole (e.g. the list of groups a user belongs to might always be fetched with that user and would average 5-10 items; probably no reason to keep it split apart)
Fetching the author is as simple as just adding the id to the URL:
var userId = 123;
new Firebase('https://INSTANCE.firebaseio.com/users/'+userId);
To fetch a list of posts belonging to a certain user, either maintain an index of that users' posts:
/posts/$post_id/...
/my_posts/$user_id/$post_id/true
var fb = new Firebase('https://INSTANCE.firebaseio.com');
fb.child('/my_posts/'+userId).on('child_added', function(indexSnap) {
fb.child('posts/'+indexSnap.name()).once('value', function(dataSnap) {
console.log('fetched post', indexSnap.name(), dataSnap.val());
});
});
A tool like Firebase.util can assist with normalizing data that has been split for storage until Firebase's views and advanced querying utils are released:
/posts/$post_id/...
/my_posts/$user_id/$post_id/true
var fb = new Firebase('https://INSTANCE.firebaseio.com');
var ref = Firebase.util.intersection( fb.child('my_posts/'+userId), fb.child('posts') );
ref.on('child_added', function(snap) {
console.log('fetched post', snap.name(), snap.val();
});
Or simply store the posts by user id (depending on your use case for how that data is fetched later):
/posts/$user_id/$post_id/...
new Firebase('https://INSTANCE.firebaseio.com/posts/'+userId).on('child_added', function(snap) {
console.log('fetched post', snap.name(), snap.val());
});

Knockoutjs how to data-bind observable array members based on IDs

I'm not if the title explains what I need to achieve or not but I can change it later if some has a better suggestion.
I'm using KO to manage a whole bunch of data on the client side.
Here's the basic.
I have a list of training sessions
Each has a list of training session parts
Each training session parts are referencing items kept in other lists. For example, I have a list of activities (ex: biking, running, swimming, etc.)
Each activity is identified by an ID which is used in the training session parts to identify which activity was used for a particular session.
Now, all these list are stored as observable arrays, and each member of the lists are observables (I use KO.Mapping to map the JSON coming from the server)
When I display a training session in my UI, I want to display various information coming from various lists
Duration: 1h30
Activity: Biking
Process: Intervals
The only information I have in order to link the training session to its component is an ID which is fine. What I'm not sure is how to data-bind the name (text) of my activity to a <p> or <div> so that the name will change if I edit the activity (by using some functionality of the application).
The training session only has the ID to identify the activity, so I don’t know how to bind the name of the activity based on its ID.
Hopefully this makes senses and someone can help me figure it out. I found lots of info on how to bind to observable array but nothing addressing ID and linked information.
The easiest way would probably be to make your own constructors and link the data by hand. You can use mapping if you really want to, but you'll basically have to do the same manual linking, only in a more verbose format.
This is the fiddle with the example implementation: http://jsfiddle.net/aKpS9/3/
The most important part of the code is the linking, you have to take care to create the activity objects only once, and use the same objects everywhere, as opposed to creating new activity objects for the parts.
var TrainingSession = function(rawData, actualActivities){
var self = this;
self.name = ko.observable(rawData.name);
self.parts = ko.observableArray(ko.utils.arrayMap(rawData.parts, function(rawPart){
return ko.utils.arrayFirst(actualActivities(), function(ac){
return ac.ID() == rawPart.ID;
})
}));
}
var Activity = function(rawData){
var self = this;
self.ID = ko.observable(rawData.ID);
self.name = ko.observable(rawData.name);
}
var MainVM = function(rawData){
var self = this;
//first create an array of all activities
self.activities = ko.observableArray(ko.utils.arrayMap(rawData.activities, function(rawAc){
return new Activity(rawAc);
}));
self.trainingSessions = ko.observableArray(ko.utils.arrayMap(rawData.trainingSessions, function(session){
return new TrainingSession(session, self.activities);
}));
}

OOP, MVC - Models and Objects

I'm building a site with CodeIgniter, and my I have a model called Blog_model.
Within Blog_model, there are methods to pull a list of posts for a specific topic, for example, getPopularPosts().
getPopularPosts() queries the posts table for a list of posts with a topic_id matching the one specified and sorts them by popularity. So, that's one query against the entire table of posts (let's assume this will be very large eventually) to find all posts with topic_id x.
Then, foreach result as an individual post id, it creates a new Post object. The Post class constructs a post by setting the field id.
To return the contents of a Post, I assign $post->getPost();, which queries the posts table again to return the entire row for the given id.
This organization (AFAIK) follows a nice object oriented principle. But now, for every posts (again, let's assume thousands, millions, whatever...), I have to first query for a list of ids and then again to get each post's content. If I'm returning 30 posts, that means 31 separate queries.
Alternatively, I could break the object oriented pattern and pull * for each post in posts where topic_id = x. Then, I have one query that returns all 30 posts, but now I don't feel so object oriented.
What to do?
There is no reason to have that many queries. You're basically just looking for X number of posts that are from a particular topic ID... you should return this as one object and then iterate through the result in PHP because it is significantly faster to do it that way once you get to the point of having millions of rows
You should go about it more like this:
class blog_model extends CI_Model {
function __construct(){
parent::__construct();
}
function getPopularPosts($cat_id){
/* Using method chaining here since you sound like you
really want to utilize everything OO CI has to offer */
$posts = $this->db->select('id, title, post_info')
->where('topic_id', $topic_id)
->get('posts');
if($posts->num_rows() > 0){
return $posts;
}else{
return FALSE;
}
}
}
Then your controller would look like this:
class blog extends CI_Controller {
function __construct() {
parent::__construct();
}
function blog_posts($popular_post_id) {
$this->load->model('blog_model');
$posts = $this->blog_model->getPopularPosts($popular_post_id);
if(!empty($posts){
foreach($posts as $post){
echo $post->id;
echo $post->title;
echo $post->post_info;
}
}else{
echo 'There are no posts';
}
}
}
There is no benefit (and actually a big problem) with generating a ton of queries in the fashion that you currently have it set up, vs generating one object from the query and iterating through each of the rows in the controller and doing whatever you need with the data.

Resources