Backbone datatypes - type casting? - javascript

It just took me over an hour to find out that a Backbone query on a collection was failing because I queried the wrong data type.
So this query failed because I used the wrong data type for id:
element = collection.findWhere({id: "123", att: true});
This one worked and returned a model from the collection.
element = collection.findWhere({id: 123, att: true});
The reason was that I took the id from a DOM element.
I am interfacing a lot with the DOM in my application.
Is there an option in Backbone that would allow me to make it more lenient in regards to data types?

One option is to override your models parse method and so a toString on the id coming in. Then you'll have strings from the dom and in your model.
http://backbonejs.org/#Model-parse
Personally I'd prefer to explicitly cast my queries instead using parseInt but they're both options

Related

Can I save a JS object (with methods) in MongoDB?

I have some objects that encode text formatting methods and css styles, and I'd like to save them in a MongoDB collection (using Mongoose). The objects are a more complicated version of this:
const myStyle = {
book: {
templates: ["/authors/. ", "/title/. ", "/date/. "],
authors: {
format: formatAuthors
},
title: {
format: formatTitle,
style: {fontStyle: "italic"}
}
}
}
Does anyone know how to send this this sort of thing to a server and save it in a MongoDB collection? According to the Mongoose documentation, Object is not a valid schemaType, so I can't just save it straightforwardly as a JS object.
You can add methods through the Schema.methods field.
SchemaName.methods.methodName = function(){...}
Also take a look at this example here for basic mongoose usage.
Object is not a valid mongoose schema type but Mixed is.
An "anything goes" SchemaType, its flexibility comes at a trade-off of
it being harder to maintain. Mixed is available either through
Schema.Types.Mixed or by passing an empty object literal.
You can read more about it using the above link.
In your case as long as the data you want to save is valid JS object you will be able to insert it.
Please note however that since it is a schema-less type there are some performance limitations when using Mixed as well as you need to call .markModified(path) when changed as again stated in the docs.
No, you can't save methods to mongodb

Append to an arary field in Firestore

I'm using Firebase and Vuejs to create an database element, which has object array inside.
That's how the field looks, and I want to add tasks through the form into the 'moreTasks' as an array.
I tried using this, but it just creates new entity in the database.
db.collection('Tasks').add({
tasker: this.tasker.taskerName
})
I also tried checking API but I couldnt understand the refs, because I was using different methods to achieve that goal.
creatTask() {
db.collection('Tasks').add({
task_id: this.task_id,
name: this.name,
What would be correct way to approach this problem?
You can append an item to an array using FieldValue.arrayUnion() as described in the documentation. For example:
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});
The accepted answer used to be correct but is now wrong. Now there is an atomic append operation using the arrayUnion method:
https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array
This is true as long as you are using firestore and not real time db (which I assume is the case from the tags)

How to remove a property from document - mongo / loopback

I have an old property on one of my models, and I'd like to remove it from all the documents in a collection. I've tried posting via /upsertWithWhere using the id to update by:
passing in undefined for the value which results in "http error 400 bad request"
passing in null which just sets the property to null
I also was thinking I could do a regular POST and just overwrite each document, but these particular documents are large and I'd rather not do that.
Is there a way to simply patch it?
Edit: Need an answer that implements this Via the Loopback API.
This query should do the trick:
db.collection('collection_name').update({},{$unset: {"old_property": ""}}, {multi:true})
Obviously, just make sure you insert into "old_property" the field name of that old property.
Explaining the query a little further...
"{}" matches all documents in the collection
"{$unset: {"old_property": ""}" removes the field(s) specified
"{multi:true}" (An optional field for update) Allows you to update multiple documents when set to true
Used this as a reference: https://docs.mongodb.com/manual/reference/method/db.collection.update/#multi-parameter

Mongoose behavior and schema

I am learning nodejs along with mongodb currently, and there are two things that confuse me abit.
(1),
When a new Schema and model name are used (not in db), the name is changed into its plural form. Example:
mongoose.model('person', personSchema);
in the database, the table will be called "people" instead.
Isn't this easy to confuse new developer, why has they implemented it this way?
(2),
Second thing is that whenever I want to refer to an existing model in mongoDb (assume that in db, a table called people exists). Then in my nodejs code, I still have to define a Schema in order to create a model that refer to the table.
personSchema = new mongoose.Schema({});
mongoose.model('person',personSchema);
The unusual thing is, it does not seem to matter how I define the schema, it can just be empty like above, or fill with random attribute, yet the model will always get the right table and CRUD operations performs normally.
Then what is the usage of Schema other than defining table structure for creating new table?
Many thanks,
Actually two questions, you usually do better asking one, just for future reference.
1. Pluralization
Short form is that it is good practice. In more detail, this is generally logical as what you are referring to is a "collection" of items or objects rather. So the general inference in a "collection" is "many" and therefore a plural form of what the "object" itself is named.
So a "people" collection implies that it is in fact made up of many "person" objects, just as "dogs" to "dog" or "cats" to "cat". Not necessarily "bovines" to "cow", but generally speaking mongoose does not really deal with Polymorphic entities, so there would not be "bull" or "bison" objects in there unless just specified by some other property to "cow".
You can of course change this if you want in either of these forms and specify your own name:
var personSchema = new Schema({ ... },{ "collection": "person" });
mongoose.model( "Person", personSchema, "person" );
But a model is general a "singular" model name and the "collection" is the plural form of good practice when there are many. Besides, every SQL database ORM I can think of also does it this way. So really this is just following the practice that most people are already used to.
2. Why Schema?
MongoDB is actually "schemaless", so it does not have any internal concept of "schema", which is one big difference from SQL based relational databases which hold their own definition of "schema" in a "table" definition.
While this is often actually a "strength" of MongoDB in that data is not tied to a certain layout, some people actually like it that way, or generally want to otherwise encapsulate logic that governs how data is stored.
For these reasons, mongoose supports the concept of defining a "Schema". This allows you to say "which fields" are "allowed" in the collection (model) this is "tied" to, and which "type" of data may be contained.
You can of course have a "schemaless" approach, but the schema object you "tie" to your model still must be defined, just not "strictly":
var personSchema = new Schema({ },{ "strict": false });
mongoose.model( "Person", personSchema );
Then you can pretty much add whatever you want as data without any restriction.
The reverse case though is that people "usually" do want some type of rules enforced, such as which fields and what types. This means that only the "defined" things can happen:
var personSchema = new Schema({
name: { type: String, required: true },
age: Number,
sex: { type: String, enum: ["M","F"] },
children: [{ type: Schema.Types.ObjectId, ref: "Person" }],
country: { type: String, default: "Australia" }
});
So the rules there break down to:
"name" must have "String" data in it only. Bit of a JavaScript idiom here as everything in JavaScript will actually stringify. The other thing on here is "required", so that if this field is not present in the object sent to .save() it will throw a validation error.
"age" must be numeric. If you try to .save() this object with data other than numeric supplied in this field then you will throw a validation error.
"sex" must be a string again, but this time we are adding a "constraint" to say what the valid value are. In the same way this also can throw a validation error if you do not supply the correct data.
"children" actually an Array of items, but these are just "reference" ObjectId values that point to different items in another model. Or in this case this one. So this will keep that ObjectId reference in there when you add to "children". Mongoose can actually .populate() these later with their actual "Person" objects when requested to do so. This emulates a form of "embedding" in MongoDB, but used when you actually want to store the object separately without "embedding" every time.
"country" is again just a String and requires nothing special, but we give it a default value to fill in if no other is supplied explicitly.
There are many other things you can do, I would suggest really reading through the documentation. Everything is explained in a lot of detail there, and if you have specific questions then you can always ask, "here" (for example).
So MongoDB does things differently to how SQL databases work, and throws out some of the things that are generally held in "opinion" to be better implemented at the application business logic layer anyway.
Hence in Mongoose, it tries to "put back" some of the good things people like about working with traditional relational databases, and allow some rules and good practices to be easily encapsulated without writing other code.
There is also some logic there that helps in "emulating" ( cannot stress enough ) "joins", as there are methods that "help" you in being able to retrieve "related" data from other sources, by essentially providing definitions where which "model" that data resides in within the "Schema" definition.
Did I also not mention that "Schema" definitions are again just objects and re-usable? Well yes they are an can in fact be tied to "many" models, which may or may not reside on the same database.
Everything here has a lot more function and purpose than you are currently aware of, the good advice here it to head forth and "learn". That is the usual path to the realization ... "Oh, now I see, that's what they do it that way".

Breezejs automatic GUID parsing

I am using Breezejs in 'NoDB' mode, meaning I write my metadata by hand. When I create a Breeze query with OData parameters I add a filter by id, say
new breeze.Predicate('iD', datacontext.breeze.FilterQueryOp.Equals, myId)
The var myId is indeed a GUID value (though it's defined as a String), but in my DB and in both my server-side and client-side model it's a string (I can't change the DB structure). the property definition in my metadata model is
dataProperties: {
...
iD: { dataType: DataType.String },
...
}
(I know the property name looks weird, but I have to use this syntax since I have the breeze.NamingConvention.camelCase.setAsDefault() on my datacontext, and the property's name on the DB is ID uppercased)
When I execute the query I see that the corresponding oData filter option in the WebAPI url is like
$filter=ID eq guid'65BEB144-5C0C-4481-AC70-5E61FDAA840D'
which leads me to this server error: No coercion operator is defined between types 'System.Guid' and 'System.String'.
Is there a way to disable this automatic 'parsing' of GUIDs and leave them as strings?
I have temporarily solved this by removing the parsing directly inside breeze's source code so that my webAPI call would look like
$filter=ID eq '65BEB144-5C0C-4481-AC70-5E61FDAA840D'
but I don't like this solution and I would be glad if there was a better one, like parametrize this behaviour in some way. I didn't find anything about this on Breeze's official website.
Breeze uses its metadata to determine that datatype of each property in a query and then uses this information to generate the correct OData filter. So your metadata definition of ID as a string should be correct.
However, in order to perform this operation breeze needs to know the EntityType of your query. For example in the following query
var q = EntityQuery.from("Foo").where(....)
breeze needs to know the EntityType that "Foo" ( a resourceName) corresponds to. Once it has the entity type it can correctly format any filters for specific properties of this entityType. If breeze does not have 'EntityType', then it falls back to guessing about the datatype of each property. In your case, its guessing that the datatype is a 'Guid'
So the fix is to either tell the query directly about the EntityType that you are querying
var q = breeze.EntityQuery.from("Foo).where(....).toType(FoosEntityType);
or you can handle it more globally via via the MetadataStore.setEntityTypeForResourceName method.
breeze.MetadataStore.setEntityTypeForResourceName("Foo", FoosEntityType);
var q = breeze.EntityQuery.from("Foo).where(....); // your original query

Categories

Resources