How can I create friendly URLs with MongoDB/Node.js? - url

For example suppose in designing a blog application I want something like
domain.com/post/729
Instead of
domain.com/post/4f89dca9f40090d974000001
Ruby has the following
https://github.com/hakanensari/mongoid-slug
Is there an equivalent in Node.js?

The id in MongoDB is actually a hexadecimal value to convert that into a numerical value you can use the following code to search for numerical value in the database like 1, 2, 3.. and this code will convert that value into appropriate hex
article_collection.db.json_serializer.ObjectID.createFromHexString(id)
where article_collection is your collection object

There are a few ways :
1- Assuming you are trying to provide a unique id to each blog post .
Why not overwrite the '_id' field of your documents in the blogs collection ?
Sample document would be :
{ "_id" : 122 , "content" : { "title: ..... }
You will have to look out for a method to generate an autoincrement id though, which is pretty easy.
This type of primary keys are however not recommended.
http://www.mongodb.org/display/DOCS/How+to+Make+an+Auto+Incrementing+Field
2- Let the _id field remain as it is, and additionaly store a key 'blogid' which is an integer, you will have to run ensureIndex on 'blogid` field though to make access by blogid fast. Storage overhead would be minor, as you will be storing a keyname and an integer more in your document.
Sample document would be :
{ "_id" : xxxxxxxxxx ,"blogid" : 122, "content" : { "title: ..... }

There are a bunch of different projects on GitHub like https://github.com/dodo/node-slug and https://github.com/stipsan/String.Slugify.js but they focus on making valid URLs out of strings (usually the post subject or article title). I haven't seen any that take a random number and some how produce a shorter random (?) and unique number.
Personally I just have a token field on my post object that contains a unique value that is shorter than just using the DB id directly (and a tiny bit more secure). If you are using Mongoose, the token can be generated automatically by hooking the pre 'Save' event on your Mongoose model.

Related

using string as id

I am making a KMM app using SQLDelight for the cache and recently I changed my database entities to use Text(String) for the id field instead of Int, now i am getting an error when inserting, I might just be missing some sqlDelight knowledge
here is my table:
CREATE TABLE sidework_Entity(
id TEXT NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
employees TEXT NOT NULL,
todoToday INTEGER AS Boolean DEFAULT 0
);
here is my insert method:
insertSidework:
INSERT OR REPLACE
INTO sidework_Entity(
id,
name,
employees,
todoToday
) VALUES (?,?,?,?);
here is my error:
statement aborts at 5: [INSERT OR REPLACE
INTO sidework_Entity(
id,
name,
employees,
todoToday
) VALUES (?,?,?,?)] datatype mismatch
I think it is most likely the Primary Key i have set on the id field or something of that sort but the documentation is a bit short.
The solution to this problem is actually running a migration. Although deleting the app to clear the database cache is a valid solution for testing purposes. For an app in production, this isn't the correct approach.
Documentation for running Migration
Stackoverflow answer with explanation

Vapor 4 Relationships and Models requiring an ID property name

I'm trying to setup parenting within an app (Vapor 4) and although its achievable, I have run across the issue or at least a limitation that results in less meaningful property names being used within the Model.
Vapor 4 requires the #ID property to be named 'id' (var id: ...), whereas in previous version the property name was definable and therefore more meaningful name.
For example the User table: Our user data uses the Username as a unique key (not the primary key) so the User model is defined as such:
// 'Unique key for the record.'
#ID(custom: "sysid", generatedBy: .database)
var id: Int?
// Unique login name
#Field(key: "username")
var username: String?
// Password for this login.
#Field(key: "password")
var password: String
...
Makes sense and is readable, and anywhere the Model is used within the App the dev knows the Id Field is the sysid and the username is the username.
The Foreign key's in the Rule and Profile table's use Username as the foreign key (because of legacy reasons). To change it though-out the db and app is not currently possible.
Since the original implementation I have been reading up and realised the benefits of using relationships (rather than Filters and Joins).
To use relationships within Vapor 4 I have to change the Model definition to:
// 'Unique key for the record.'
#Field(key: "sysid")
var sysid: Int?
// Unique login name
#ID(key: "username")
var id: String?
// Password for this login.
#Field(key: "password")
var password: String
...
My Model definitions are less meaningful (although it does work):
Of course this means though-out the code .username now needs to be changed to .id which is far less self-explanatory.
In Vapor 3 we could define the ID Property Name to anything. It would be much easier if Fluent/Vapor 4 allowed custom Property Names like in previous versions.
I was wondering if anyone has come across this 'issue?' or has a workaround to allow the Models to continue to use meaningful names and still allow Parenting to work correctly.
I used this simple user data as an example but surely others use different/meaningful column names that suffer my .. annoyance?
Any guidance/thoughts would be appreciated Thanks
Fluent's relationship property wrappers are all based on the relationship being defined under the id property. This allows you to create a child with just the parent ID and without having to look up the parent in the DB first etc.
If you want to use something other than the ID, you'll need to either just perform the queries manually (which for parent/child is relatively simple) or duplicate the property wrappers and choose a different property.

Saving record in RavenDb with F# adding extra Id column

When I save a new F# Record, I'm getting an extra column called Id# in the RavenDb document, and it shows up when I load or view the object in code; it's even being converted to JSON through my F# API.
Here is my F# record type:
type Campaign = { mutable Id : string; name : string; description : string }
I'm not doing anything very exciting to save it:
let save c : Campaign =
use session = store.OpenSession()
session.Store(c)
session.SaveChanges()
c
Saving a new instance of a record creates a document with the Id of campaigns/289. Here is the full value of the document in RavenDb:
{
"Id#": "campaigns/289",
"name": "Recreating Id bug",
"description": "Hello StackOverflow!"
}
Now, when I used this same database (and document) in C#, I didn't get the extra Id# value. This is what a record looks like when I saved it in C#:
{
"Description": "Hello StackOverflow!",
"Name": "Look this worked fine",
}
(Aside - "name" vs "Name" means I have 2 name columns in my document. I understand that problem, at least).
So my question is: How do I get rid of the extra Id# property being created when I save an F# record in RavenDb?
As noted by Fyodor, this is caused by how F# generates a backing field when you create a record type. The default contract resolver for RavenDB serializes that backing field instead of the public property.
You can change the default contract resolver in ravendb. It will look something like this if you want to use the Newtonsoft Json.Net:
DocumentStore.Conventions.JsonContractResolver <- new CamelCasePropertyNamesContractResolver()
There is an explanation for why this works here (see the section titled: "The explanation"). Briefly, the Newtonsoft library uses the public properties of the type instead of the private backing fields.
I also recommend, instead of having the mutable property on the Id, you can put the [<CLIMutable>] attribute on the type itself like:
[<CLIMutable>]
type Campaign = { Id : string; name : string; description : string }
This makes it so libraries can mutate the values while preventing it in your code.
This is a combination of... well, you can't quite call them "bugs", so let's say "non-straightforward features" in both F# compiler and RavenDb.
The F# compiler generates a public backing field for the Id record field. This field is named Id# (a standard pattern for all F# backing fields), and it's public, because the record field is mutable. For immutable record fields, backing fields will be internal. Why it needs to generate a public backing field for mutable record fields, I don't know.
Now, RavenDb, when generating the schema, apparently looks at both properties and fields. This is a bit non-standard. The usual practice is to consider only properties. But alas, Raven picks up the public field named Id#, and makes it part of the schema.
You can combat this problem in two ways:
First, you could make the Id field immutable. I'm not sure whether that would work for you or RavenDb. Perhaps not, since the Id is probably generated on insert.
Second, you could declare your Campaign not as an F# record, but as a true class:
type Campaign( id: int, name: string, description: string ) =
member val Id = id with get, set
member val name = name
member val description = description
This way, all backing fields stay internal and no confusion will arise. The drawback is that you have to write every field twice: first as constructor argument, then as class member.

MVC EF String Length / Data Type for Signature Image

I'm using a javascript plugin called jSignature to give my MVC4 application delivery signature capture functionality. jSignature outputs the signature info in a data:image/png;base64,iVBORw0KG... string format that looks to be around 32,000 characters long. I created a property in my model called DeliverySignature as a string and am able to save and retrieve the signature data but when I pull it back in from the database it's only about 5,000 characters long. What data type do I need to be using in my model's definition and in the action method (it's being passed in to a controller to save to the db) so that it preservers the complete string length? Thank you.
I would store it in varchar(max) column.
You can keep model property type of string as strings do not have a limited length.

multilingual mongodb mongomapper

I have a category collection and each category has a array of hashes containing attributes names and units to create a inout form with, to add a product of that category.
for example category car fields - {name : length, unit : mm}, {name : weight, unit : kg}.
Problem is i would this site to be multi-lingual and therefore need to store the field names per language.
I could put them inline :
for example category car fields - {en-name : length, cn-name : ....., de-name : ....., unit : mm}
Is there a better way ?
Not sure if this is best way as i want to be able to pass a docuement of names needing to be translated to the translator for all field names for all categories, so storing this way i would have to grab all then put into another docuement then translate and inset new translated naes back!!!
Any help or ideas ?
Thanks
rick
The best way would be to put translations in locale files (in config/locales/). For example (english locale):
en:
categories:
car:
length: Length
And then something like that when displaying name of the field:
I18n.t("categories.#{category.name}.#{field_name}")
This way you can maintain only one locale file and send the other ones to the translator.
Model translation is fairly easy in MongoDB.
Here's a gist that uses a custom MongoMapper type to transparently handle localization: https://gist.github.com/828114
Your LocalizedString would look like
name: {
en: '...',
cn: '...',
de: '...'
}
The custom type just stores/returns the value for the current I18n.locale

Resources