How can I pass parameters to getter in Sequelize model? - mysql

What I'm doing:
I'm reading csv which contains data like townships, religions and so on. In the csv, they are text values. But of course in my table in the database, they are foreign_key. So to insert those, I need to map those text values to id.
It is possible to get the id like below.
const { townshipId } = await models.Township.findOne({
where: { name: township },
attributes: ["townshipId"],
raw: true,
});
The problem:
But the problem what I think is that those findOne(s) will be populated in my entire method because I have like 50 other properties besides township.
What I'm trying
I'm trying to pass township-name to a getter method, expecting its equivalent townshipId.
I found out that it is possible to use getter and setter in sequelize. But I don't find how to pass parameters to those.
My question
Am I trying the correct way to import the csv data? How can I use getters (and setters) with parameters in sequelize?

Maybe if you want to exclude columns from the result, you pass the "attributes" field like:
attributes: { exclude: ['field1','field2'] }
This way you wont show the columns "field1" and "field2" in the result.

Related

Alias Sequelize

I have this query in sequelize:
Domicilio.hasMany(User, {foreignKey: 'UserId'});
const abonados = await Domicilio.findAll({include: User});
Which result is the following:
SELECT domicilio.DomicilioId, _users.UserId AS _users.UserId, _users.UserName AS _users.UserName, _users.FullName AS _users.FullName, _users.Password AS _users.Password, _users.Documento AS _users.Documento, _users.Cuit AS _users.Cuit, _users.Email AS _users.Email, _users.FechaBajada AS _users.FechaBajada, _users.FechaContrato AS _users.FechaContrato, _users.FechaNacimiento AS _users.FechaNacimiento, _users.Phone AS _users.Phone, _users.FailedPasswordCount AS _users.FailedPasswordCount, _users.IsActive AS _users.IsActive, _users.IsLocked AS
_users.IsLocked, _users.IsTestUser AS _users.IsTestUser, _users.LastLoginDate AS _users.LastLoginDate, _users.createdAt AS _users.createdAt, _users.createdBy AS _users.createdBy, _users.deletedAt AS _users.deletedAt, _users.deletedBy AS _users.deletedBy, _users.updatedAt AS _users.updatedAt, _users.updatedBy AS _users.updatedBy, _users.CondicionIVAId AS _users.CondicionIVAId, _users.OnuId AS _users.OnuId, _users.ServicioId AS _users.ServicioId FROM domicilio AS domicilio LEFT OUTER JOIN _user AS _users ON domicilio.DomicilioId = _users.UserId;
But I don't need the ALIAS of each of the columns of table _user. E.g _user.UserId I need only the name of each column without alias. Is there any way to aproach this?
There are some ways to change the value of the returning column
First I would suggest that you fetch only the columns really needed
by you at the model endpoint that way the response is concise.
Please refer the code below in which you can see how you can provide
alias in an association, the alias you provide in there is the one
which is used during the include you can fiddle around to get the
desired behavior. Also, you can tweak your findAll with option
params like {raw: true}
Official Docs:
https://sequelize.org/master/manual/assocs.html
https://sequelize.org/master/class/lib/model.js~Model.html#static-method-findAll
Ship.belongsTo(Captain, { as: 'leader' }); // This creates the `leaderId` foreign key in Ship.
// Eager Loading no longer works by passing the model to `include`:
console.log((await Ship.findAll({ include: Captain })).toJSON()); // Throws an error
// Instead, you have to pass the alias:
console.log((await Ship.findAll({ include: 'leader' })).toJSON());
// Or you can pass an object specifying the model and alias:
console.log((await Ship.findAll({
include: {
model: Captain,
as: 'leader'
}
})).toJSON());
Second but not very recommended way is to provide a raw query with
the parameter [Do not use javascript template string to pass the
args] here you have control over the params and conditions
Docs for raw query: https://sequelize.org/master/manual/raw-queries.html
Lastly, you can use alias in attribute to customize the value's key
to anything you like
const abonados = await Domicilio.findAll({
include: User,
attributes: [['UserId', 'newUserId'], ['UserName 'newUserName']]
});
P.S: literal might also come in handy at times.

Vuejs changes order of json_encoded array, when decodes it back from props in vuejs component

Php:
$json_string = "{
"26":{"blabla":123,"group_id":1,"from":"27.08.2018","to":"02.09.2018"},
"25":{"blabla":124,"group_id":1,"from":"20.08.2018","to":"26.08.2018"},
"24":{"blabla":125,"group_id":1,"from":"20.08.2018","to":"26.08.2018"}
}"
my.blade.php template:
<my-component :records={{ $json_string }}></my-component>
MyComponent.vue:
export default {
props: ['records'],
...
mounted: function () {
console.log(this.records);
}
Output is:
{__ob__: Observer}
24:(...)
25:(...)
26:(...)
And when I use v-for, records in my table in wrong order (like in console.log output).
What I am doing wrong?
EDIT:
I figured out 1 thing:
When I do json_encode on collection where indexes are from 0 till x, than json string is: [{some data}, {some data}]
But if I do ->get()->keyBy('id') (laravel) and than json_encode, json string is:
{ "26":{some data}, "25":{some data}, "24":{some data} }
Then how I understood, issue is in different outer brackets.
In Javascript keys of objects have no order. If you need a specific order then use arrays.
Here is documentation for keyBy Laravel method: https://laravel.com/docs/5.6/collections#method-keyby
I wanted to have ids for rows data to fast and easy access without iterating over all rows and check if there is somewhere key Id which is equals with my particular Id.
Solution: not to use keyBy method in Laravel and pass json string to Vue component like following [{some data}, {some data}] (as I described in my Question Edit section) - this will remain array order as it used to be.
I found this short and elegant way how to do this, instead of writing js function by myself:
Its find() method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Example:
let row = records.find( record => record.id === idToFind );

CSV Parser through angularJS

I am building a CSV file parser through node and Angular . so basically a user upload a csv file , on my server side which is node the csv file is traversed and parsed using node-csv
. This works fine and it returns me an array of object based on csv file given as input , Now on angular end I need to display two table one is csv file data itself and another is cross tabulation analysis. I am facing problem while rendering data, so for a table like
I am getting parse responce as
For cross tabulation we need data in a tabular form as
I have a object array which I need to manipulate in best possible way so as to make easily render on html page . I am not getting a way how to do calculation on data I get so as to store cross tabulation result .Any idea on how should I approach .
data json is :
[{"Sample #":"1","Gender":"Female","Handedness;":"Right-handed;"},{"Sample #":"2","Gender":"Male","Handedness;":"Left-handed;"},{"Sample #":"3","Gender":"Female","Handedness;":"Right-handed;"},{"Sample #":"4","Gender":"Male","Handedness;":"Right-handed;"},{"Sample #":"5","Gender":"Male","Handedness;":"Left-handed;"},{"Sample #":"6","Gender":"Male","Handedness;":"Right-handed;"},{"Sample #":"7","Gender":"Female","Handedness;":"Right-handed;"},{"Sample #":"8","Gender":"Female","Handedness;":"Left-handed;"},{"Sample #":"9","Gender":"Male","Handedness;":"Right-handed;"},{"Sample #":";"}
There are many ways you can do this and since you have not been very specific on the usage, I will go with the simplest one.
Assuming you have an object structure such as this:
[
{gender: 'female', handdness: 'lefthanded', id: 1},
{gender: 'male', handdness: 'lefthanded', id: 2},
{gender: 'female', handdness: 'righthanded', id: 3},
{gender: 'female', handdness: 'lefthanded', id: 4},
{gender: 'female', handdness: 'righthanded', id: 5}
]
and in your controller you have exposed this with something like:
$scope.members = [the above array of objects];
and you want to display the total of female members of this object, you could filter this in your html
{{(members | filter:{gender:'female'}).length}}
Now, if you are going to make this a table it will obviously make some ugly and unreadable html so especially if you are going to repeat using this, it would be a good case for making a directive and repeat it anywhere, with the prerequisite of providing a scope object named tabData (or whatever you wish) in your parent scope
.directive('tabbed', function () {
return {
restrict: 'E',
template: '<table><tr><td>{{(tabData | filter:{gender:"female"}).length}}</td></tr><td>{{(tabData | filter:{handedness:"lefthanded"}).length}}</td></table>'
}
});
You would use this in your html like so:
<tabbed></tabbed>
And there are ofcourse many ways to improve this as you wish.
This is more of a general data structure/JS question than Angular related.
Functional helpers from Lo-dash come in very handy here:
_(data) // Create a chainable object from the data to execute functions with
.groupBy('Gender') // Group the data by its `Gender` attribute
// map these groups, using `mapValues` so the named `Gender` keys persist
.mapValues(function(gender) {
// Create named count objects for all handednesses
var counts = _.countBy(gender, 'Handedness');
// Calculate the total of all handednesses by summing
// all the values of this named object
counts.Total = _(counts)
.values()
.reduce(function(sum, num) { return sum + num });
// Return this named count object -- this is what each gender will map to
return counts;
}).value(); // get the value of the chain
No need to worry about for-loops or anything of the sort, and this code also works without any changes for more than two genders (even for more than two handednesses - think of the aliens and the ambidextrous). If you aren't sure exactly what's happening, it should be easy enough to pick apart the single steps and their result values of this code example.
Calculating the total row for all genders will work in a similar manner.

Meteor: how do I return data from fields in a specific object?

This should be a fairly simple one.
myobject has various properties, _id, name, createdBy, date etc
In my find query I want to only return specific fields from within myObject. So for example, what would I need to do to modify the find query below so that only name was returned?
myCollection.find({createdBy: someId}, {fields: {myObject: 1}}).fetch();
Currently this will return everything in myObject which it should do, I just want one field within myObject returned.
Here is a way to do it within the query:
myCollection.find({createdBy: someId}, {fields: {'myObject.name':
1}}).fetch();
Note the quotes around
'myObject.name'
Lets assume we are talking about posts, and a post document looks like this:
{
_id: 'abc123',
title: 'All about meteor',
author: {
firstName: 'David',
lastName: 'Weldon'
}
}
You can then extract all of the last names from all of the authors with this:
var lastNames = Posts.find().map(function(post) {
return post.author.lastName;
});
Modify the selector and options as needed for your collection. Using fields in this case may be a small optimization if you are running this on the server and fetching the data directly from the DB.

MongoDB - Dynamically update an object in nested array

I have a document like this:
{
Name : val
AnArray : [
{
Time : SomeTime
},
{
Time : AnotherTime
}
...arbitrary more elements
}
I need to update "Time" to a Date type (right now it is string)
I would like to do something psudo like:
foreach record in document.AnArray { record.Time = new Date(record.Time) }
I've read the documentation on $ and "dot" notation as well as a several similar questions here, I tried this code:
db.collection.update({_id:doc._id},{$set : {AnArray.$.Time : new Date(AnArray.$.Time)}});
And hoping that $ would iterate the indexes of the "AnArray" property as I don't know for each record the length of it. But am getting the error:
SyntaxError: missing : after property id (shell):1
How can I perform an update on each member of the arrays nested values with a dynamic value?
There's no direct way to do that, because MongoDB doesn't support an update-expression that references the document. Moreover, the $ operator only applies to the first match, so you'd have to perform this as long as there are still fields where AnArray.Time is of $type string.
You can, however, perform that update client side, in your favorite language or in the mongo console using JavaScript:
db.collection.find({}).forEach(function (doc) {
for(var i in doc.AnArray)
{
doc.AnArray[i].Time = new Date(doc.AnArray[i].Time);
}
db.outcollection.save(doc);
})
Note that this will store the migrated data in a different collection. You can also update the collection in-place by replacing outcollection with collection.