Context
Hello, we have a project we integrate with a ton of different CRMs. That means that when a new client comes in, we get all their data from their CRM and store it in our own postgresql database. This means that having fixed schemas for our application is pretty hard.
Requirements
Our app adds geographical capabilities to all the CRMs we integrate with by adding a map. Over that map, we then built some features on top. The base needs of these features are:
- Text search: common full text search.
- Filtering / colorising: filtering by range (numeric, datetime), specific values of picklist, location on map (we have a tile server for this), etc. We also support filtering by null or filled values. For example, show me all records where field
field
is null or not. - Insert speed is kind of important, because we have to make imports of hundred of thousands of records when integrating a new company. But these are less and less frequent because we are building an event-based update mechanism to be always up to date with the CRMs data.
Current solution
We chose some time ago to fully implement an entity-atribute-value (EAV) data model. This seemed the best idea given the shape of our data (more or less shapeless, due to how many different objects you have in the CRMs). The structure is more or less the usual in an EAV model:
- One table to store some core fields of the entity (id, creator, created date and so on)
- 5 tables for the 5 different built-in types we support (number, string, picklist, datetime, address)[1].
This seemed great some time ago, but now we are having some difficulties when adding new features to the system. For instance:
- Full text search: this is somewhat hard to implement for some of the field types that we support (because we need to make some data redundant).
- Adding new field types: putting all the information of a complex field type into one field only forces us to create some pretty weird code.
- The tile server we have built to implement the filtering, needs to run some pretty big and prone to error queries to combine filters by several fields.
- Model hard to understand by new joiners to the project.
Possible new solution
We were thinking about reducing the complexity of the project by combining Schemas and JSONB. Basically just store all records in just one table:
- Some fixed columns in the table with the most used values.
- Json b columns with all the fields coming from the CRM, stored there to be queried by the filter/colorising functionality. We would use GIN index to support full text search.
I have some concerns about the filtering speed. Customers are used to that feature working pretty fast. I'm unsure about how slow will it get if we store everything in a JSONB format. Right now we don't have a crazy amount of records, so I was thinking that this solution could get us to support more clients, and once we have more clients, move the filtering part to a Reversed Index solution like Elastic Search, while leaving all the other functionalities working with Postgresql.
What would you recommend in this case? Is everything clear? Please let me know if I need to clarify something!
[1] Right now we have these five fields, but they could be reduced by:
- Combining picklist table into the string one.
- Casting all datetimes to strings (we store everything in UTC and we only care about range filters, which given that all is in UTC, then alphabetical comparisons can be used to implement the datetime range filter).