I am new to sails.js. I want to select all record from a table. How to use .find() .
Specially how waterline will know from which table i want data ? Because we are not mentioning any table name in model. I know there is .query(). But is this possible within waterline basic create / update / find / delete method ?
Another question how to use prefix for table name in sails.js ? Like i want to use sails_product as table name.
I am new to sails.js. I want to select all record from a table. How to use .find() .
If your model name is, for example, Book, you'd select all Book records with
Book.find()
.exec(function(err, books) {
if (err) return res.serverError();
console.log(books); // 'books' is an array of the found records
})
Specially how waterline will know from which table i want data ? Because we are not mentioning any table name in model. I know there is .query(). But is this possible within waterline basic create / update / find / delete method ?
Yes, it's possible. You don't have to deal with table names and such at all with waterline, all you need is your model name. Create, update, delete all work the same way as the find example above - so ModelName.actionName().
Another question how to use prefix for table name in sails.js ? Like i want to use sails_product as table name.
By default, waterline uses the model name lowercased as the corresponding table name. You can, however, overwrite this in your model settings. For example, if you have your model defined in a file called Book.js, its contents would look like this:
module.exports = {
attributes: {
name: {
type: 'String',
required: true
},
price: {
type: 'float'
}
},
tableName: 'custom_book_table'
}
This way the actual table created in the database will be called custom_book_table, while you'll still refer to your model in find queries etc. as Book.
Here's links to both Waterline and Sails docs to get you going. In model/query related issues, I'd definitely search from Waterline docs first.
Related
Sequelize gives you the ability to define a many to many association between tables which adds some extra functionality to a Model instance.
I have a Users table and I have defined a self-association on the table like so:
User.belongsToMany(models.User, { through: 'Friends', as: 'friends', foreignKey: 'userId' });
This gives the instance of the User model a couple of extra methods like user.getFriends(). So far so good.
What I want to do is to get all users who aren't friends of our instance. Something like user.getNonFriends(). Would that be possible using Sequelize?
A quick solution I can think of is, you could get the list of friends of the user A from the database. Using that result you can get the friends list that is not in the user's A list. Here is an example in code
const friends = user.getFriends();
const friendIds friends.map(friend => friend.id)
Friend.findAll({ where: {
id: { $notIn: [...friendIds] }
}
})
(EDITED to clarify that I want to delete/drop an attribute from the database when it is deleted from an object)
I have a small Sails application with a schema-less model that allows attributes to be added and saved to the database (currently just the sails-disk file system adaptor for testing purposes).
The problem I am having is that I can't find a way to permanently delete attributes from the database.
When I delete an attribute on an object which is a model instance I also want the attribute dropped from the database. This will be useful when I move to an object database like MongoDB and have objects with dynamically created attributes.
Deleting an attribute using delete object[attributeName] and then saving with the instance method object.save() does not work, the deleted attributes still remain.
For example if I have this object:
{
"name": "Chair",
"colour": "white"
}
Let's say I want to remove the colour attribute to replace it with a material attribute like this:
{
"name": "Chair",
"material": "pine"
}
After updating the object in the database the new material attribute is added, but the deleted colour attribute is not removed.
So the end result in the database will be this:
{
"name": "Chair",
"colour": "white",
"material": "pine"
}
So this is not the outcome I am after.
Is there a way to permanently delete/drop attributes from an object in the database using Sails/Waterline?
I am sure it is too late for this but I had the same issue. What I did was just create a new object and delete the old one. If you want to do this programatically, just compare the key of the current object and the old one. The problem with this is that you must also update all related models (and collections) with the new id.
You can't by default "unset" an attribute because structured SQL databases do not work that way. You can set the attribute to NULL is the most you can do with straight SailsJS. In a structured DB like MySql, MSSQL, Oracle, PGSQL when you do not supply an attribute the DB will insert a default value (NULL or other prescribed value by the schema definition) or throw an error at you.
For NoSQL DB like Mongo they do have an "unset" option which Sails does not support out of the box. In Sails you would have to do a native query using sails.model["name"].getDatastore().manager then run the native Mongo update query using $unset to remove the attribute.
const db = sails.model["products"].getDatastore().manager;
await db.collection("products").update(
{ sku: "unknown" },
{ $unset: { quantity: "", instock: "" } });
** updateMany can also be used the same way for multiple records at the same time.
ref: https://docs.mongodb.com/manual/reference/operator/update/unset/
Otherwise document replacement (cringe) is the only other alternative as stated before.
I've been searching a lot about Sails.js multi tenancy capabilities and I know that such a feature is not yet implemented. My initial idea was to build multi tenant app by creating one database per tenant.
Since I realized that I can't do such a thing in Sails.js yet, I tried a different aproach by creating only one database ( POSTGRES ) but with lots of schemas, each one representing a tenant. My problem is that I can't/I dunno ( don't even know if that is possible in Sails/Postgres adapter ) how to dynamically ( on runtime ) define what schema a given object should query aganist, based on the logged user.
Has anyone faced a problem like this? How can I proceed?
Sorry for English and thanks.
In my experience adding in the model does not work.
The only thing that worked for me was using the meta call to specify the schema.
await Users.create(newUser).meta({ schemaName: 'admin' });
A bit cumbersome, but it is working.
Hope this helps someone.
I thinks is an issue of the waterline sequel adapter, based in this answer.
The way to do it is add a property in the model
meta: {
schemaName: 'schema'
},
but is not working, you can't define multiple schemas, only takes the user as an schema, if the property schema is set in true ins the config/models.js, the definition of a schema for every table is not working.
The clue is inside the sails-postgresql adapter code - several of its helpers include this bit:
var schemaName = 'public';
if (inputs.meta && inputs.meta.schemaName) {
schemaName = inputs.meta.schemaName;
} else if (inputs.datastore.config && inputs.datastore.config.schemaName) {
schemaName = inputs.datastore.config.schemaName;
}
So indeed the driver is looking for a schema named public by default, unless a different value is provides via calls to meta() as described above, OR the schema name is configured application-wide.
To configure the schema name for all models, a schemaName property needs to be included in the configuration of the postgresql datastore, which occurs in datastore.js:
...
default: {
adapter: 'sails-postgresql',
url: 'postgresql://username:password#localhost:5432/your_database_name',
schemaName: 'your_schema_name_here'
}
Once this is in place, you don't have to append meta({ schemaName: 'blah'}) to any of the queries. I struggled with this for a couple of days and have finally solved it in this manner.
First of all excuse me since I don't know how it is called in computer since:
For each of my document types in my mongo app I want to define a structure, with every field defined with its constraints, validation patterns and, generally, roles that can view modify and delete this document.
For example: Book:
{
name: "Book",
viewRoles: ["Admin","User"],
createRoles: ["Admin"],
modifyRoles: ["Admin", "User"],
fields: [
{
id:"title",
name:"Book Title",
validation: "",
maxLength: 50,
minLength: 3,
required: true
},
{
id:"authorEmail",
name:"Email of the Author",
validation: "email",
maxLength: 50,
minLength: 3,
required: false
}
]
}
Then if I have this "schema" for all of my documents, I can have one view for creating modifying and showing this "entities".
I also want to have the ability to create new document types, modify their fields through admin panel of my application.
When I google "mongo dynamic schema", "mongo document meta design" I get useless information.
My question is how it is called -- when I want to have predefined schema of my documents and have the ability to modify it. Where I can get more information about how to design such systems?
Since you tagged this as having a Meteor connection, I'll point you to Simple Schema: https://github.com/aldeed/meteor-simple-schema/. I use it, along with the related collection2 package. I find it's a nice way to document and enforce schema design. When used with the autoform package, it also provides a way to create validated forms directly from your schema.
I think you are looking for how to model your data. The below link might be helpful:
http://docs.mongodb.org/manual/data-modeling/
I also want to have the ability to create new document types, modify
their fields through admin panel of my application.
For Administrative activities you may look into the options given in:
http://docs.mongodb.org/ecosystem/tools/administration-interfaces/
And once you are done, you might want to read this as a kick off:
https://blog.serverdensity.com/mongodb-schema-design-pitfalls/
In Mongo DB you don't create collections. You just start using them. So you can't define schemas before hand. The collection is created on the first insert you make to the collection. Just make sure to ensure Index on the collection before inserting documents into it:
db.collection.ensureIndex({keyField: 1})
So it all depends on maintaining the structure of the documents inserted to the collection rather than defining the collection.
I have a situation using backbone.js where I have a collection of models, and some additional information about the models. For example, imagine that I'm returning a list of amounts: they have a quantity associated with each model. Assume now that the unit for each of the amounts is always the same: say quarts. Then the json object I get back from my service might be something like:
{
dataPoints: [
{quantity: 5 },
{quantity: 10 },
...
],
unit : quarts
}
Now backbone collections have no real mechanism for natively associating this meta-data with the collection, but it was suggested to me in this question: Setting attributes on a collection - backbone js that I can extend the collection with a .meta(property, [value]) style function - which is a great solution. However, naturally it follows that we'd like to be able to cleanly retrieve this data from a json response like the one we have above.
Backbone.js gives us the parse(response) function, which allows us to specify where to extract the collection's list of models from in combination with the url attribute. There is no way that I'm aware of, however, to make a more intelligent function without overloading fetch() which would remove the partial functionality that is already available.
My question is this: is there a better option than overloading fetch() (and trying it to call it's superclass implementation) to achieve what I want to achieve?
Thanks
Personally, I would wrap the Collection inside another Model, and then override parse, like so:
var DataPointsCollection = Backbone.Collection.extend({ /* etc etc */ });
var CollectionContainer = Backbone.Model.extend({
defaults: {
dataPoints: new DataPointsCollection(),
unit: "quarts"
},
parse: function(obj) {
// update the inner collection
this.get("dataPoints").refresh(obj.dataPoints);
// this mightn't be necessary
delete obj.dataPoints;
return obj;
}
});
The Collection.refresh() call updates the model with new values. Passing in a custom meta value to the Collection as previously suggested might stop you from being able to bind to those meta values.
This meta data does not belong on the collection. It belongs in the name or some other descriptor of the code. Your code should declaratively know that the collection it has is only full of quartz elements. It already does since the url points to quartz elements.
var quartzCollection = new FooCollection();
quartzCollection.url = quartzurl;
quartzCollection.fetch();
If you really need to get this data why don't you just call
_.uniq(quartzCollecion.pluck("unit"))[0];