prisma icon indicating copy to clipboard operation
prisma copied to clipboard

Aggregate Raw not working when trying to `$match` on `_id` (needs to be an `ObjectId` but it's not a valid input)

Open pedrobrun opened this issue 2 years ago • 18 comments

new aggregate raw support

@matthewmueller Do you guys know about any issue that the raw aggregation support is having? I'm trying to run a pipeline though it, which I know for a fact that is working because I wrote it and tested it at first on MongoDB Compass.

return this.prisma.user.aggregateRaw({
      pipeline: [
        {
          $match: {
            _id: id,
          },
        },
        {
          $project: {
            communityId: 1,
          },
        },
        {
          $lookup: {
            from: 'Community',
            localField: 'communityId',
            foreignField: '_id',
            as: 'community',
          },
        },
        {
          $project: {
            communityId: 0,
          },
        },
        {
          $unwind: {
            path: '$community',
          },
        },
        {
          $lookup: {
            from: 'CommunityNft',
            localField: 'community._id',
            foreignField: 'communityId',
            as: 'communityNft',
          },
        },
        {
          $unwind: {
            path: '$communityNft',
          },
        },
        {
          $lookup: {
            from: 'NftBenefit',
            localField: 'communityNft._id',
            foreignField: 'communityNftId',
            as: 'nftBenefits',
          },
        },
        {
          $lookup: {
            from: 'Voucher',
            localField: 'nftBenefits._id',
            foreignField: 'nftBenefitId',
            as: 'vouchers',
          },
        },
      ],
    });

This operation is returning an empty array.

Originally posted by @pedrobrun in https://github.com/prisma/prisma/issues/6712#issuecomment-1227771299

pedrobrun avatar Aug 25 '22 21:08 pedrobrun

Could you provide us with a sample of data or a way to insert it and then provide us with the expected output from running this query?

danstarns avatar Aug 26 '22 09:08 danstarns

Could you provide us with a sample of data

@danstarns sure! here's some mock data: aggregation_sample_data.zip

pedrobrun avatar Aug 26 '22 18:08 pedrobrun

@Jolg42 @danstarns Were you able to reproduce it?

pedrobrun avatar Aug 31 '22 12:08 pedrobrun

@danstarns btw I forgot to send you the expected result, sorry. But basically it is just meant to return everything I looked up in the query. An array of objects that relate through the foreign and local fields of the $lookup queries.

pedrobrun avatar Aug 31 '22 13:08 pedrobrun

@pedrobrun No we didn't check this yet, I just changed the label to reflect that is now actionable (= there is something to try a reproduction). We have a lot of issues to look at, so any additional information is welcome, like your:

  • MongoDB version
  • Prisma version from prisma -v
  • Anything that you think could be relevant

Jolg42 avatar Aug 31 '22 13:08 Jolg42

@Jolg42 ok, got it! Thanks for the update :) Prisma's version was 4.2.1. Mongo's locally installed version is 5.0.7, but the development db is hosted on Atlas. Tbh there's no additional information. I had to migrate to Mongoose as I had some deadlines close and this was a core feature and I didn't want to have to hit 4+ collections separately. Once this is sorted out I'll probably move back to Prisma though.

pedrobrun avatar Aug 31 '22 13:08 pedrobrun

I imported the data with https://github.com/prisma/prisma/files/9435702/aggregation_sample_data.zip

mongoimport --host localhost:27018 --db 15013 --collection community --file community.json --jsonArray
mongoimport --host localhost:27018 --db 15013 --collection communitynft --file communitynft.json --jsonArray
mongoimport --host localhost:27018 --db 15013 --collection nftbenefit --file nftbenefit.json --jsonArray
// note I had to fix the json first and put [] around the object
mongoimport --host localhost:27018 --db 15013 --collection user --file user.json --jsonArray
mongoimport --host localhost:27018 --db 15013 --collection voucher --file voucher.json --jsonArray

Jolg42 avatar Sep 07 '22 09:09 Jolg42

Can reproduce in our internal dev version 4.4.0-dev.30

Here is the script to reproduce

import { PrismaClient } from "@prisma/client";
import { ObjectId } from "bson";
import { MongoClient } from "mongodb";

async function main() {
  const prisma = new PrismaClient();

  const client = await MongoClient.connect(
    "mongodb://root:prisma@localhost:27018/15013?authSource=admin"
  );
  const coll = client.db("15013").collection("user");
  const cursor = coll.aggregate([
    {
      $match: {
        // as string doesn't work
        // _id: "63053c88b472e7492f517dcd",
        // but works as ObjectID!
        _id: new ObjectId("63053c88b472e7492f517dcd"),
      },
    },
  ]);
  const resultFromMongoDriver = await cursor.toArray();
  console.log({ resultFromMongoDriver });
  await client.close();

  const usersFromFindMany = await prisma.user.findMany();
  console.log({ usersFromFindMany });

  const rawResult1 = await prisma.user.aggregateRaw({
    pipeline: [
      // @ts-ignore
      {
        $match: {
          // as string doesn't work (needs to be ObjectID)
          // _id: "63053c88b472e7492f517dcd",
          //
          // But ObjectID throws a TypeError... (Note: ignoring it with  @ts-ignore doesn't help)
          //
          // Type '{ $match: { _id: ObjectId; }; }' is not assignable to type 'InputJsonValue'.
          // Types of property '$match' are incompatible.
          //   Type '{ _id: ObjectId; }' is not assignable to type 'InputJsonValue | null | undefined'.
          //     Types of property '_id' are incompatible.
          //       Type 'ObjectId' is not assignable to type 'InputJsonValue | null | undefined'.
          //         Type 'ObjectId' is not assignable to type 'InputJsonObject'.
          //           Index signature for type 'string' is missing in type 'ObjectId'.
          _id: new ObjectId("63053c88b472e7492f517dcd"),
        },
      },
    ],
  });
  console.log({ rawResult1 });

  prisma.$disconnect();
}

main();

output

ts-node main.ts
{
  resultFromMongoDriver: [
    {
      _id: new ObjectId("63053c88b472e7492f517dcd"),
      email: '[email protected]',
      password: '$2b$12$wuytZTYUGeyF39DqPsRLu.mZAOT/iK2T8uz5tUMZpH4PQWRqtyajC',
      name: 'admin',
      address: 'string',
      role: 'ADMIN',
      status: 'ACTIVE',
      communityId: new ObjectId("6305304e27e9634fbaac6699"),
      updatedAt: 2022-08-23T20:45:59.828Z,
      createdAt: 2022-08-23T20:45:59.826Z
    }
  ]
}
{
  usersFromFindMany: [
    {
      id: '63053c88b472e7492f517dcd',
      address: 'string',
      communityId: '6305304e27e9634fbaac6699',
      createdAt: 2022-08-23T20:45:59.826Z,
      email: '[email protected]',
      name: 'admin',
      password: '$2b$12$wuytZTYUGeyF39DqPsRLu.mZAOT/iK2T8uz5tUMZpH4PQWRqtyajC',
      role: 'ADMIN',
      status: 'ACTIVE',
      updatedAt: 2022-08-23T20:45:59.828Z
    }
  ]
}
{ rawResult1: [] }

Jolg42 avatar Sep 07 '22 09:09 Jolg42

Any progress on this issue ? Please fix this...

viktornord avatar Sep 23 '22 14:09 viktornord

I have same issue

Boromir1994 avatar Sep 23 '22 14:09 Boromir1994

@Jolg42 any updates on this?

ran-konneto avatar Oct 11 '22 14:10 ran-konneto

Unfortunately no news, I'm not part of the team that will work on this. I can only say it's on their radar, so they will pick this up one day, but they have to prioritize with other issues.

Jolg42 avatar Oct 11 '22 15:10 Jolg42

having same issue. Any update on this?

Anyone has any workaround?

srinivasdareddy avatar Dec 13 '22 12:12 srinivasdareddy

@srinivasdareddy Unfortunately I'm not very hopeful that this'll be fixed in the very near future. There are currently 2.3k issues open. What I did was migrating to mongoose

pedrobrun avatar Dec 13 '22 16:12 pedrobrun

bump

Vaasu-Dhand avatar Jan 09 '23 00:01 Vaasu-Dhand

@pedrobrun Try this: $match: { _id: { $oid: id } }

Hope it helps. :)

heteibako avatar Jan 13 '23 07:01 heteibako

Thanks @heteibako that's working for me :)

QasimRRizvi avatar Feb 07 '23 12:02 QasimRRizvi

+1 I've looked for solving for several hours. Thanks @heteibako

Bricks666 avatar Jun 23 '23 19:06 Bricks666

Thanks @heteibako for the solution. You have saved me a great deal of my time.

theguywhocodes96 avatar Oct 06 '23 06:10 theguywhocodes96

This may be relevant for those wondering where the $oid came from https://www.prisma.io/docs/concepts/components/prisma-schema/relations#mongodb (subject matter pasted below if the link ever stops working)

MongoDB

For MongoDB, Prisma currently uses a normalized data model design, which means that documents reference each other by ID in a similar way to relational databases.

The following document represents a User (in the User collection):

{ "_id": { "$oid": "60d5922d00581b8f0062e3a8" }, "name": "Ella" }

The following list of Post documents (in the Post collection) each have a authorId field which reference the same user:

[
  {
    "_id": { "$oid": "60d5922e00581b8f0062e3a9" },
    "title": "How to make sushi",
    "authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
  },
  {
    "_id": { "$oid": "60d5922e00581b8f0062e3aa" },
    "title": "How to re-install Windows",
    "authorId": { "$oid": "60d5922d00581b8f0062e3a8" }
  }
]

This data structure represents a one-to-many relation because multiple Post documents refer to the same User document.

Evilscaught avatar Oct 17 '23 18:10 Evilscaught

@heteibako , @Evilscaught , @Bricks666 , @QasimRRizvi , @theguywhocodes96 , what about, if i want to use $in, not single id

{ '_id': { $oid: '669f6d9148b7b4ef0faf1412' } } its okay

{ '_id': { $in: [{ $oid: '669f6d9148b7b4ef0faf1412' }, { $oid: '669f6d9148b7b4ef0faf1413' }] } } its not okay, not getting needed data

Could anybody help for this case ?

This?

 $in: ids?.map((id: string) => ({  $oid: id  }))

$match: { 'your-key-here': { $in: ids?.map((id: string) => ({ $oid: id })) } }

heteibako avatar Aug 02 '24 08:08 heteibako

@heteibako For querying with multiple ids, I've had to wrap my ids in an ObjectId.

import { ObjectId } from 'mongodb';

const match = { $match: { 'your-key-here': { $in: (ids || []).map( (id: string) => ({ $oid: ObjectId(id) }) ) } } }

// Do something with match

* for future reference, this example is using "prisma": "4", "mongodb": "^4.9.0" and node version 16.15.0

Evilscaught avatar Aug 02 '24 13:08 Evilscaught

@Evilscaught Interesting. The code above is from a project that I was working on, and I had not needed to wrap the id in ObjectId. But good to know that it works. My Prisma version is: 5.16.0

heteibako avatar Aug 02 '24 14:08 heteibako