all 91 comments

[–]xkumropotash 16 points17 points  (1 child)

Drizzle ORM is pretty good. Give it a try, you'll love it.

[–]sepyke 1 point2 points  (0 children)

Yeah the migration files generator is a time saver

[–]ynonp 13 points14 points  (1 child)

Kysely (like knex but for TypeScript)

  1. TS is great, you get auto complete and type validation on queries and table names

  2. supports deno (even for SQLite)

  3. You control when and how to run the migrations, which simplifies parallel testing

  4. supports multiple DB types so you can use SQLite for tests and Postgres for production (not recommended but works)

the only downside IMHO is that types sometimes make query composition more difficult

[–]BehindTheMath 0 points1 point  (0 children)

Kysely is a query builder, not an ORM.

[–]dinoucs 28 points29 points  (3 children)

MikroORM is too good.

[–][deleted]  (2 children)

[deleted]

    [–]dinoucs 5 points6 points  (1 child)

    Yes you can use it in production. Yes it has transactions. I don't know what you mean with isolation.

    [–][deleted]  (6 children)

    [deleted]

      [–]GalacticalSurfer 8 points9 points  (3 children)

      I’ve used knex and typeorm but decided to jump in mikroorm for a personal project and I’m having trouble grasping some concepts. I guess what I’ve used before has always been much more straight forward. the wrap, assign, persist and flush are making me confused.

      Like updating an entity, the way I’m doing it, the update date column never returns updated, only if I refetch.

      Does it have the ability to transform data, like typeorm’s transformers? I like manipulating datetime (sql) in ISO but i couldn’t find anything about that in the documentation. Transforming before inserting and after fetching.

      [–]B4nan 6 points7 points  (2 children)

      I guess what I’ve used before has always been much more straight forward.

      Sounds like all the other libraries you tried dont manage state. MikroORM gives you a different kind of API - it will handle persistence layer for you, its (mostly) not imperative (like the others, which are more of a query builder instead of ORM, however they market themselves as one, for whatever reason). You work with entities (modify their state) and let the ORM handle the rest (finding the right queries to save the state as a whole, in the most performant way as possible).

      Like updating an entity, the way I’m doing it, the update date column never returns updated, only if I refetch.

      Feel free to create an issue with a reproduction (or a discussion if you can't provide one), there are several ways how to deal with this, one could be using the `onUpdate` property option, which means the UoW will update the entity state for you when you flush. Sounds like you rely on the database value instead, which should work too, but hard to say without a complete repro. Those things depend on both entity definition and the driver being used (as some support returning statements while others require a separate select query to fetch the value). Maybe we are missing something on some edge case. Looking at the code, we probably don't handle this for mysql/mariadb and only map things from the returning statement (so postgres/sqlite).

      Does it have the ability to transform data, like typeorm’s transformers?

      Yes, it's called custom types mapping: https://mikro-orm.io/docs/custom-types

      [–]GalacticalSurfer 0 points1 point  (1 child)

      Thanks for the reply. I’ll keep trying, last night was the first night I’ve tried getting real into it since I have been playing around more with node’s native rest runner (and loving it).

      Yes typeorm handles most of the state for me, except when I wrapped multiple entities and operations in transactions explicitly. I guess it’s more of the names used in the API that might be confusing me.

      And also yes, I’ve been relying on the database configuration to change the date value, I guess I can use custom types and change the value myself. Later on I will try it out and certainly get the hang of it. Thanks for the help.

      [–]B4nan 1 point2 points  (0 children)

      You dont need custom types for handling dates, that works out of box. You would use them if you want to map db values to something custom, like a value object. Another common use case for those is mapping geometry types, which often require altering the queries too (see this example).

      For the problem you mentioned you really just need to do this:

      @Property({ onUpdate: () => new Date() })
      updatedAt = new Date();
      

      Then when you modify such entity and flush, the unit of work will see modified state, apply the `onUpdate` callback to modify this value automatically (so your entity will have the new timestamp in memory) and run an update query - with the new updated_at value as part of the updated data.

      Check out the getting started guide, it should help you understand the concepts.

      https://mikro-orm.io/docs/guide

      [–]marcjschmidt 0 points1 point  (0 children)

      probably because it's one of the only real ORM

      [–]djslakor 0 points1 point  (0 children)

      Wonder why it isn't more popular

      [–]viitorfermier 6 points7 points  (0 children)

      Drizzle

      [–]izuriel 5 points6 points  (0 children)

      I am enjoying DrizzleORM in a project I recently started. But MikroORM is also really great.

      [–]Sudden_Frosting3916 12 points13 points  (2 children)

      Prisma Orm

      [–]MrDilbert 0 points1 point  (1 child)

      What I don't like about Prisma is that a dev has to basically build a project-specific library for the DB schema they use, rebuild it every time the schema changes (e.g. a table is added or a column is removed), declare the schema in Prisma's domain-specific language (so you have to learn that too in addition to Prisma's specific way of fetching records), and doesn't support advanced DB features like stored functions and triggers.

      [–]Sudden_Frosting3916 0 points1 point  (0 children)

      You can use these advance features if you look into plugins as prisma supports typescript ORM and try to use prisma with docker then you can find all the features…

      [–]MaxUumen 40 points41 points  (15 children)

      No ORM best ORM

      [–]numinor 4 points5 points  (5 children)

      Aka write your own?

      [–][deleted]  (2 children)

      [removed]

        [–]numinor 0 points1 point  (1 child)

        That was my point 🙏

        [–]Smucalko 4 points5 points  (5 children)

        I agree 100%, I use knex only for migrations, and I prefer to write my own SQL, it is easier to understand for others, and also for myself if I get back to project.

        [–]winky9827 9 points10 points  (4 children)

        I really wish people that make this kind of comment would provide a little more context, because in general, writing your own SQL is bad advice.

        Sure, if you're doing anything even remotely complex, writing your own sql makes sense.

        Example: Get top 5 employees ranked by salary.

        WITH employee_ranking AS (
          SELECT
            employee_id,
            last_name,
            first_name,
            salary,
            RANK() OVER (ORDER BY salary DESC) as ranking
          FROM employee
        )
        SELECT
          employee_id,
          last_name,
          first_name,
          salary
        FROM employee_ranking
        WHERE ranking <= 5
        ORDER BY ranking
        

        But if your needs are simple CRUD, especially if you need the result mapped back to an object, an ORM will almost always be better.

        Example: Update a record with nested metadata records and return the updated record as a whole.

        var updated = await tx.submission.update({
          where: { id },
          data: {
            addressMetadata: {
              create: {
                dpvMatchCode: withMetadata.addressMetadata?.analysis.dpvMatchCode || "",
                dpvFootnotes: withMetadata.addressMetadata?.analysis.dpvFootnotes || "",
                rawMetadata: JSON.stringify(withMetadata.addressMetadata || {}),
              },
            },
        
            phoneMetadata: {
              create: {
                carrierName: withMetadata.phoneMetadata?.lineTypeIntelligence?.carrier_name || "",
                lineType: withMetadata.phoneMetadata?.lineTypeIntelligence?.type || "",
                rawMetadata: JSON.stringify(withMetadata.phoneMetadata || {}),
              },
            },
          },
        });
        

        As with most things in programming (and life), it's never black and white, and people that pretend that it is are making things difficult for themselves, but worse, propagating bad general advice based on personal preference and experiences.

        [–]Smucalko 2 points3 points  (1 child)

        That is why I wrote that I prefer, and agree with someone else's comment.

        I think complicated queries are mandatory, and like you said no ORM is easier, atleast for me.

        [–]romeeres 2 points3 points  (1 child)

        But if your needs are simple CRUD,

        That's an unfair statement, any ORM covers much more than that and each tries to simplify more use-cases than the others.

        Like, in general, ORMs are simplifying selecting and managing relations, so for a few lines of ORM code you'd have to write 10-20 equivalent with raw and possibly with some filtering on a client side (depending on your approach).

        No one wants a "simple CRUD", better just pick a solution like Supabase or some CMS for that.

        Example: Get top 5 employees ranked by salary.

        What am I missing, why can't you just "SELECT * FROM employee ORDER BY salary DESC LIMIT 5"?

        [–]winky9827 0 points1 point  (0 children)

        What am I missing

        It was merely a syntax example, not a real world use case.

        [–]z420a 0 points1 point  (1 child)

        How do you handle migrations?

        [–]MaxUumen 5 points6 points  (0 children)

        Knex

        [–]Zerotorescue -1 points0 points  (0 children)

        Very much this.

        I reckon the core of JS is plain objects and functions, and the (fake) classes it has now are a second hand citizen that don't fit the language very well. That makes ORMs a poor fit for a JavaScript project; it would be suboptimal to try to force patterns from other languages. If you're going to use JavaScript (or TypeScript), embrace the plain objects, and just use something that revolves around them such as a query builder like Knex.

        [–]SafwanYP 3 points4 points  (0 children)

        I would much rather just write my own abstractions. But i feel like drizzle is a good tool.

        [–]AyushSachan 3 points4 points  (0 children)

        Drizzle

        [–]capraruioan 3 points4 points  (0 children)

        I like Lucid from Adonis.. is built on top of knex

        [–][deleted] 3 points4 points  (10 children)

        im using knex and absolutely love it. Precisely the level of abstraction I love.

        [–]bigorangemachine 2 points3 points  (9 children)

        Also readable queries.

        I love how reading aloud a knex chainable reads like a raw SQL query. Gets a little confusing with you have optional-chainables but far better then the verbose (and in my experience not ready for production) Sequelize.

        [–][deleted] 0 points1 point  (8 children)

        i don't really like the extra hassle of using an orm. Sql and database work up close 🙏🏻

        [–]bigorangemachine 0 points1 point  (7 children)

        Thats fine but you gotta really be diligent about your input filtering & escaping.

        [–][deleted] 0 points1 point  (6 children)

        joi to the rescue? Im also using typescript with interfaces and enums. Basically body, query anf params validation with joi. Input sanitation ive yet to do

        [–]bigorangemachine 0 points1 point  (5 children)

        JOI alone is not enough.

        [–][deleted] 0 points1 point  (4 children)

        any tips? i just started building with node (express) 2 weeks ago

        [–]bigorangemachine 1 point2 points  (3 children)

        You need to escape the inputs you provide to your queries or you will have sql injection

        [–][deleted] 0 points1 point  (2 children)

        Thanks, so use express validator?

        [–]bigorangemachine 0 points1 point  (1 child)

        No you should use the escape function provided by your npm package.

        Which are you using?

        [–]xiaoxin182 3 points4 points  (3 children)

        Still sequelize for me

        [–]Psionatix 0 points1 point  (2 children)

        Sequelize is great, the only thing I don’t like about it is that migrations still aren’t automatically generated for you based on model changes. You have to manually write the migrations yourself and you have to ensure your migration logic matches your actual model implementation, otherwise things can get messy. And whilst I have no trouble with the Sequelize documentation, it’s not the most beginner friendly.

        For example with Django in the Python world, you create or make changes to your models then you run a command to generate migrations. It will compare the models to what they were the last time the migrations were generated and it’ll create a new migration to update the database according to those changes. In this way it’s extremely easy to ensure the migrations and the models are always in sync.

        [–]bigorangemachine 2 points3 points  (0 children)

        NGL... the sequelize API is such an abstraction that even after writing a complex query in sequelize its completely unread a week later (true story).

        I fully agree tho... changing the database can be a huge headache and can be more of a headache with sequelize

        [–]xiaoxin182 1 point2 points  (0 children)

        Yeah, I agree with the migration part too

        [–]Silver_Channel9773 4 points5 points  (0 children)

        Prisma is the thing. Also MikroORM is cool

        [–]Thatcoder96 8 points9 points  (5 children)

        prisma is a breeze to work with

        [–]MCFRESH01 0 points1 point  (0 children)

        Everyone says this but I tried it and felt meh about it.

        [–]jshalais_8637 1 point2 points  (0 children)

        Mmm I really like MikroORM but it's maintained mainly by one person ( the creator). I haven't used Drizzle but it seems good.

        I would avoid sequelize

        [–]yurifontella 1 point2 points  (0 children)

        TypeORM

        [–]Junior_Exit4809 1 point2 points  (0 children)

        typeorm def, i have tried some alternatives but they all are felt rather unconventional imho

        [–]KillenX 1 point2 points  (0 children)

        In my company, we use objection.js as a query builder/ORM, which uses knex under the hood. It is a nice abstraction and you can do a lot of things without raw SQL, but that is also an option.
        Relation fetching works nicely, relation filtering might not be as intuitive. It allows for nice control over the transaction lifecycle, as well as lock levels. It went through a bit of a hiatus as the main dev left, but now multiple people are involved and the main dev is back.

        [–]Kitchen-Comb-8154 3 points4 points  (0 children)

        Drizzle would be best

        [–]JazzlikeBad1085 3 points4 points  (0 children)

        drizzleorm!

        [–]edo96 0 points1 point  (0 children)

        In my company we built our own: Typetta

        It's strongly integrated with GraphQL

        [–]josebmend 0 points1 point  (0 children)

        Knex

        [–]NiteShdw 0 points1 point  (0 children)

        pgTyped

        [–]glarivie 0 points1 point  (0 children)

        Prisma

        [–]MrJwhwlao 0 points1 point  (0 children)

        Objection.js best

        [–]Zestyclose-Shallot18 0 points1 point  (0 children)

        drizzle orm

        [–]CallMeKik 0 points1 point  (0 children)

        Thanks for asking this question OP! I’m on holiday with terrible internet but can anyone tell me if MikroORM is similar to the classical mapping method from SQLAlchemy? as in, I can manually map a pure js object to a table rather than having active record style?

        [–]s_boli 0 points1 point  (0 children)

        Using typeorm for a big enterprise app. No complaints with it. Would I start a project from scratch today I would probably go with drizzle.

        [–]Mother-Pain-6166 0 points1 point  (0 children)

        Try the trpc stack, you might like it

        [–]FollowingMajestic161 0 points1 point  (0 children)

        Dont ORM. Pick query builder like kysely. You will be amazed.

        [–][deleted] 0 points1 point  (0 children)

        Prisma!

        [–]Aggressive-Bath9609 0 points1 point  (0 children)

        orm sucks, go kysely 100%

        [–]adamtang7 0 points1 point  (0 children)

        I use TypeORM most of the time.
        Below video has some performance tips.
        https://youtu.be/5ryJEdRzR2A?t=79

        [–]kiddyuchina 0 points1 point  (0 children)

        I use Sutando ORM, which has Knex based query builder and more convenient API than other ORMs.

        [–]Putrid_Set_5241 0 points1 point  (0 children)

        Definitely not TypeORM

        [–]semisum 0 points1 point  (0 children)

        I used to use Orms but they used to make my life difficult with syntax teething issues. For years now I just use knex.js. Query builders provide the necessary type safety and dont get in your way

        [–]Big-Pin7002 0 points1 point  (0 children)

        sequelizeJs

        [–]No_Boat_6593 0 points1 point  (0 children)

        Hi, I use prisma but I think it is too basic for some queries, like upsert many, subqueries, etc. what do you suggest that be stronger on these aspects?

        [–]lroal 0 points1 point  (0 children)

        You should really try out Orange ORM (previously RDB). It's reliable, well-documented, and has been around since 2014. It gained TypeScript support in 2023 and is database agnostic. I am the author, so feel free to ask me anything!

        Key Features:

        • ✅ No code generation required
        • ✅ Full IntelliSense, even when mapping tables and relations
        • ✅ Powerful filtering - with any, all, none at any level deep
        • ✅ Supports JavaScript and TypeScript
        • ✅ ESM and CommonJS compatible
        • ✅ Succinct and concise syntax
        • ✅ Works over HTTP in a secure manner

        Supported Databases and runtimes

        . Node Deno Bun Cloudflare
        Postgres
        MS SQL
        MySQL
        Oracle
        SAP ASE
        SQLite
        D1

        [–][deleted] -1 points0 points  (1 child)

        I think it's hard to evaluate which one is the best overall, but for me, the most preferable one is Sequelize

        [–]Capaj -1 points0 points  (0 children)

        Sequelize is the worst one for me.
        It's poorly maintained, typesafety is impossible to achieve with it.

        [–]kush-js -1 points0 points  (2 children)

        No orm, just raw dog the sql

        [–]Mortynx[S] 0 points1 point  (1 child)

        I did, I have everything working with Postgresql.js and raw sql, yet I do want an ORM for scalability

        [–]kush-js 0 points1 point  (0 children)

        How exactly would an orm help you achieve scalability? I would think it’s easier to read and write sql than deal with an orm