typeorm: Search by objectId doesn't work for MongoDB

Issue type:

[ ] question [ x] bug report [ ] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ x] mongodb [ ] mssql [ ] mysql / mariadb [ ] oracle [ ] postgres [ ] cockroachdb [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

TypeORM version:

[x ] latest [ ] @next [ ] 0.x.x (or put your version here)

Steps to reproduce or a small repository showing the problem:

import { ObjectID } from "mongodb";
import { Column, Entity, Index, ObjectIdColumn } from "typeorm";

@Entity()
@Index(["clientId", "name"], { unique: true })
export class User {
  @ObjectIdColumn()
  public id: ObjectID;

  @Column()
  public companyRef: ObjectID;

  @Column()
  public name: string;

  @Column()
  public mobile: number;
}
const repository = getMongoRepository(EventSchema);
const id = "hex-string";
// These work
repository.findOne(id);
repository.find({where:{ _id: id }});

// But this doesn't
repository.find({id: id, mobile: 021029022});

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 9
  • Comments: 28

Commits related to this issue

Most upvoted comments

It doesn’t work, because _id is NOT instance of ObjectID. To make it work, you should manually create ObjectID instance, something like this

//Note, that I use constructor from mongodb and type from typeorm, but they shouldn't have the different names if they're in different files
import { ObjectID } from 'mongodb';
import { ObjectID as ObjectIDType} from 'typeorm'

@Entity()
export class User {
  @ObjectIdColumn()
  _id: ObjectIDType;

  @Column()
  name: string;
}

const userId = '5d961d865ede2a35d0f51207';

const userRepository = connection.getMongoRepository(User);
const user = await userRepository.findOne({
 _id: new ObjectID(userId)
});

//or just use
const user = await userRepository.findOne(userId)

Hey guys,

I was just reading the issue here and experimenting with some stuff and randomly I’ve nailed it:

async findById(id: string): Promise<UserEntity> {
   return await this.userRepository.findOne(id);
}

Basically one have to pass only the id to basically find by id in mongo. This is my entity class:

@Entity('users')
export class UserEntity {
  @ObjectIdColumn()
  id: string;

  @Column({ unique: true })
  email: string;

  @Column()
  password: string;
}

It is definitely not a fix, more like a workaround.

Please read documents carefully it’s not an issue. You should not use find in mongodb like that way. Use findOne instead.

import {getMongoRepository} from "typeorm";

const userRepository = getMongoRepository(User); // or connection.getMongoManager
const timber = await userRepository.findOne({ firstName: "Timber", lastName: "Saw" });

And if you want to use find you should use where inside of it.

The only work around is:

import { ObjectId } from 'bson'; // this is necessary

@Entity()
class Entity {
  @ObjectIdColumn()
  id: ObjectId // <= this type is from the mongodb package or bson package and it is not the one from typeorm
}

then in your code to find a document by id you do:

entityRepository.findOne({
  _id: new ObjectId('your string id here')
} as any)

For quick reference, I think this summarizes the issue: Screen Shot 2019-04-25 at 12 03 48 PM

For context:

import {Column, Entity, ObjectID, ObjectIdColumn} from "typeorm";
import {Category} from "./Category";

@Entity()
export class Post {

    @ObjectIdColumn()
    id: ObjectID;

    @Column()
    title: string;

    @Column()
    text: string;

    @Column(type => Category)
    categories: Category[];

}

I think this is a feature request and can be added! Simply if database type was mongo, change id => _id and the run the query

I can second this. This is very confusing. Being forced to use _id means that mongo-specific code is leaking into my business logic and even the front-end unless we do a bunch of manual serialization.

@pleerock is there a way to make this less confusing?

please reopen this issue…

The following is work for me, but when i use import { ObjectID } from 'typeorm';, it is not work.

import { ObjectID } from 'mongodb';

  ...
  const product = await productRepository.findOne(Product, {
    where: {
      _id: new ObjectID(req.query.id as string),
    },
  });

Want to use id instead of _id. no more appropriate solution, please reopen this issue.

Please, reopen this issue. It makes no sense to use _id when you explicitly decorate the ID attribute with @ObjectIdColumn

This issue is closed without a solution. My scenario:

import { Entity, Column, ObjectIdColumn } from 'typeorm';

@Entity()
class User {
  @ObjectIdColumn()
  id: ObjectId
}
// doesn't work
userRepository.findOneBy({ id });

// works - but typescript will complain about the type mismatch (id is a string in this context)
userRepository.findOne(id);

Some more debugging info from another project: I’m using Typeorm version ^0.2.15

This works: Screen Shot 2019-04-25 at 12 39 31 PM

This fails with a duplicate ID error. Screen Shot 2019-04-25 at 12 40 54 PM

Here’s the error:

BulkWriteError: E11000 duplicate key error collection: admin.session index: _id_ dup key: { : ObjectId('5cc138bc6ae997f91f44b6a3') }
    at OrderedBulkOperation.handleWriteError (/[REDACTED]/node_modules/mongodb/lib/bulk/common.js:1061:11)
    at resultHandler (/[REDACTED]/node_modules/mongodb/lib/bulk/ordered.js:167:23)
    at /[REDACTED]/node_modules/mongodb-core/lib/connection/pool.js:397:18
    at process._tickCallback (internal/process/next_tick.js:61:11)
export abstract class BaseModel {
    init(data: InitPayload<this>) {
        Object.keys(data).forEach((key) => {
            this[key] = data[key]
        })
        return this
    }

    @ObjectIdColumn()
    _id: ObjectID | string

    @TimestampWithZone()
    created: number

    @TimestampWithZone()
    updated: number
}

@Entity()
export class Session extends BaseModel {
    @Column()
    directionDomain: string

    @Column()
    referrerDomain: string

    @Column(type => ClientLocation)
    clientLocation: ClientLocation

    @Column(type => ChatMessage)
    messages: ChatMessage[]
}

@tien So you saying that when you use id code doesn’t work but when you use _id it does?

@deepchudasama sorry for the confusion, when I try repository.findOne({id: id, mobile: 021029022}); It also doesn’t work. But when I change the the entity definition from

@ObjectIdColumn()
  public id: ObjectID;
// To
@ObjectIdColumn()
  public _id: ObjectID;
// And do
const repository = getMongoRepository(EventSchema);
const id = "hex-string";
repository.find({_id: id, mobile: 021029022});

It work. Which is kind of confusing as the example usage of mongo use id instead of _id