# Source: https://mikro-orm.io/blog/mikro-orm-5-8-released.md

# MikroORM 5.8 released

·

<!-- -->

6 min read

[![Martin Adámek](https://avatars1.githubusercontent.com/u/615580?s=460\&v=4)](https://github.com/B4nan)

[Martin Adámek](https://github.com/B4nan)

Author of MikroORM

After a longer pause, I am pleased to announce next feature release - [MikroORM v5.8](https://github.com/mikro-orm/mikro-orm/releases/tag/v5.8.0), probably the last one before [v6](https://github.com/mikro-orm/mikro-orm/discussions/3593). While I don't blog about the feature releases very often, I feel like this one deserves more attention. Why?

## Fine-grained control over upserting[​](#fine-grained-control-over-upserting "Direct link to Fine-grained control over upserting")

Upserting, so `em.upsert` and `em.upsertMany`, is relatively new addition to the [EntityManager toolkit](https://mikro-orm.io/docs/entity-manager#upsert). It allows you to run `insert on conflict` queries (and works in MongoDB too!) to ensure a record exists in the database, updating its state when necessary.

The default behavior was to always prefer using the primary key for the `on conflict` condition, and fallback to the first unique property with a value. While this was a sane default, it quickly appeared it won't work very well for some use cases - the most common one being entities with UUID primary keys. In this case, we cannot use the primary key for the conflict resolution - but we often generate this value via property initializers, so the default logic would prefer it (and fail to find a match). A way around this was using the POJO signature of `em.upsert`, and not providing the UUID value in the data - but that leads to counter issues with drivers that don't have an easy way to generate UUID on server side (via database default). And it is not just about drivers like SQLite, where we don't have a UUID function on database level - the very same problem comes with PostgreSQL too, when you want to generate a UUID v7 key - those are not yet supported out of box.

MikroORM v5.8 now offers a fine-grained control over how the upserting logic works. You can use the following advanced options now:

* `onConflictFields?: (keyof T)[]` to control the conflict clause
* `onConflictAction?: 'ignore' | 'merge'` used ignore and merge as that is how the QB methods are called
* `onConflictMergeFields?: (keyof T)[]` to control the merge clause
* `onConflictExcludeFields?: (keyof T)[]` to omit fields from the merge clause

Here is a more complex example, note that it would work with both signatures the same way - we can pass in an array of entities too, and leverage the runtime defaults we set via property initializers.

```
const [author1, author2, author3] = await em.upsertMany(Author, [{ ... }, { ... }, { ... }], {
  onConflictFields: ['email'], // specify a manual set of fields pass to the on conflict clause
  onConflictAction: 'merge',
  onConflictExcludeFields: ['id'],
});
```

This will generate query similar to the following:

```
insert into "author" 
  ("id", "current_age", "email", "foo")
  values
    (1, 41, 'a1', true),
    (2, 42, 'a2', true),
    (5, 43, 'a3', true)
  on conflict ("email") 
  do update set
    "current_age" = excluded."current_age",
    "foo" = excluded."foo" 
  returning "_id", "current_age", "foo", "bar"
```

It might not be obvious on the first sight, but since we specified `onConflictExcludeFields: ['id']` in this example, the primary key value will be narrowed via the `returning` clause - in the third item, we specify a wrong primary key (`5`) which is not matching the database, and as a result, we get a property hydrated entity with the correct primary key we get from the database.

There were other hidden improvements made to the upserting, namely the `qb.onConflict()` now maps property names to column names properly, the `em.upsertMany` runs in batches now (respecting the global `batchSize` option), and the result of `em.upsert/Many` now contains all the values with database defaults, so it truly represents the current database state and not just the data provided by you in the payload.

## Filters with Joined loading strategy[​](#filters-with-joined-loading-strategy "Direct link to Filters with Joined loading strategy")

Another important change is about [filters](https://mikro-orm.io/docs/filters). Previously, the filters were applied only when using the `select-in` strategy, as part of the where condition. Since v5.8, when using the `joined` strategy, filters will be also applied to the query, via join on conditions. This means the strategies should now behave the same finally. I am currently considering whether we should change the default strategy in v6, as this was the last big feature missing in the `joined` strategy implementation.

A connected change to this one is how the `populateWhere` option works - those conditions are now also applied as `join on` conditions when using the `joined` strategy.

## New `Collection` helpers[​](#new-collection-helpers "Direct link to new-collection-helpers")

Lastly, there are several new `Collection` methods, so its interface is more in-line with the `Array` prototype:

* `find()` to find the first matching element
* `map()` to map elements
* `filter()` to filter elements
* `reduce()` to map the array to a dictionary
* `slice()` to extract a portion of the elements

And few more convenience methods:

* `exists()` to check if a matching element exists
* `isEmpty()` to check if the collection is empty
* `indexBy()` to map the items to a dictionary, if there are more items with the same key, only the first one will be present.

The `indexBy()` can be pretty helpful, let's have a closer look at what it is capable of. If we specify only the first parameter, we get a map of the elements indexed by a given key:

```
// user.config is `Collection<Option>` where `Option` has a `key` and `value` props
const config = user.config.indexBy('key');
// {
//   option1: { id: 5, key: 'option1', value: 'Value 1' },
//   option2: { id: 12, key: 'option2', value: 'Value 2' },
//   option3: { id: 8, key: 'option3', value: 'Value 3' },
// }
```

The second parameter allows to map to a value directly instead of mapping to the target entity:

```
const config = user.config.indexBy('key', 'value');
// {
//   option1: 'Value 1',
//   option2: 'Value 2',
//   option3: 'Value 3',
// }
```

## Smaller improvements worth mentioning[​](#smaller-improvements-worth-mentioning "Direct link to Smaller improvements worth mentioning")

* readonly transactions (native feature of MySQL and PostgreSQL)
* comments and hint comments on SQL queries (e.g. for query optimizers and logging purposes)
* global `disableIdentityMap` and `resultCache` options
* `Migration` class now offers `getEntityManager()` helper which accepts the current transaction context

## What about v6?[​](#what-about-v6 "Direct link to What about v6?")

I mentioned in the beginning that this might be the final feature release of the 5.x branch, so where are we with the next major? There are still few refactors I want to undergo, before I consider it done, but most of them are already in progress and shouldn't be too hard to resolve.

* support for propagation with `useDefineForClassFields: true`
* rework `Date` mapping to work via mapped types
* rework hydration of STI entities to support shadowing of properties with same type

I was focusing on the 5.x branch recently, so the v6 development was a bit stalled, but this is going to change now. But there is one significant improvement that was merged into v6 just yesterday - the [initial dataloader support for loading `Collection` and `Reference` properties](https://github.com/mikro-orm/mikro-orm/pull/4321)!

It will still take some time, definitely weeks, maybe a few months, but worst case, we should see the next major released by the end of the 2023.

## Getting started guide[​](#getting-started-guide "Direct link to Getting started guide")

I got one more thing to share. Maybe you missed it, but the work-in-progress **Getting Started guide** is now public. It's far away from complete, but it should already provide some value, especially to beginners. Be sure to check it out, and as always, feedback is very welcome!

<https://github.com/mikro-orm/guide>

**Tags:**

* [typescript](https://mikro-orm.io/blog/tags/typescript.md)
* [javascript](https://mikro-orm.io/blog/tags/javascript.md)
* [node](https://mikro-orm.io/blog/tags/node.md)
* [sql](https://mikro-orm.io/blog/tags/sql.md)