GraphQLGuide / apollo-datasource-mongodb

Apollo data source for MongoDB
MIT License
285 stars 64 forks source link

collection.find(...).toArray is not a function? #8

Closed GimignanoF closed 4 years ago

GimignanoF commented 4 years ago

I've implemented the example code, however when the resolver hits the data source, this error pops up

TypeError: collection.find(...).toArray is not a function
      at _dataloader.default.ids (E:\test-graphql\node_modules\apollo-datasource-mongodb\dist\cache.js:31:6)    
      at dispatchQueueBatch (E:\test-graphql\node_modules\apollo-datasource-mongodb\node_modules\dataloader\index.js:246:22)
      at dispatchQueue (E:\test-graphql\node_modules\apollo-datasource-mongodb\node_modules\dataloader\index.js:233:5)
      at E:\test-graphql\node_modules\apollo-datasource-mongodb\node_modules\dataloader\index.js:70:20
      at process._tickCallback (internal/process/next_tick.js:61:11)

This is how I create the data source in it's own file

const { MongoDataSource } = require("apollo-datasource-mongodb");

class ProductPages extends MongoDataSource {
  getProductPage(id) {
    return this.findOneById(id);
  }
}

exports.ProductPagesDataSource = new ProductPages(ProductPageModel);

This is how I add it to the ApolloServer

const { ProductPagesDataSource } = require("../graphql/schema/schema");
const app = new ApolloServer({
  ...
  dataSources: () => ({
    productPages: ProductPagesDataSource
  })
});

And in the resolver I call it like this (I use graphql-compose with graphql-compose-mongoose for my schema, but that shouldn't be an issue since I can make it work using the DataLoader package)

schemaComposer.Query.addFields({
  page: ProductPageSchema.get("$findById").wrapResolve(next => rp => {
    return rp.context.dataSources.productPages.getProductPage(rp.args._id);
  })
});

What am I doing wrong?

lorensr commented 4 years ago

Is ProductPageModel a Mongoose model? If yes, does it have a .collection?

this.collection is set here: https://github.com/GraphQLGuide/apollo-datasource-mongodb/blob/master/src/datasource.js#L20

And then this.collection.find().toArray() is called when you do findOneById

Also, you're only creating a single instance of ProductPages. You should be doing new ProductPages inside the dataSources function so that an instance is created for each request.

GimignanoF commented 4 years ago

Yes, ProductPageModel is a mongoose model that does have a .collection field. I changed my code to this now

const { MongoDataSource } = require("apollo-datasource-mongodb");

class ProductPages extends MongoDataSource {
  getProductPage(id) {
    return this.findOneById(id);
  }
}

module.exports = ProductPages;

and in the app.js class

// Import the Product Page Data Source
const ProductPageDataSource = require("../data/product-page/product-page");
// Import the Product Page Model
const {
  model: ProductPageModel
} = require("../models/product-page/product-page");
const app = new ApolloServer({
  ...
  dataSources: () => ({
    productPages: new ProductPageDataSource(ProductPageModel)
  }),
  ...
});

but still got the same error :/

lorensr commented 4 years ago

Are you using the latest version? (0.2.0)

If yes, I don't know what the issue is. If you can modify this test in a way that gets it to fail (or add a new failing test), I should be able to fix it:

https://github.com/GraphQLGuide/apollo-datasource-mongodb/blob/master/src/__tests__/datasource.test.js#L78-L83

GimignanoF commented 4 years ago

I've run that test, and this is the output

 PASS  src/__tests__/cache.test.js
 FAIL  src/__tests__/datasource.test.js (7.238s)
  ● Mongoose › data source

    TypeError: Cannot read property '_id' of null

      79 |     const users = new Users(UserModel)
      80 |     users.initialize()
    > 81 |     const user = await users.findOneById(alice._id)
         |                                                ^
      82 |     expect(user.name).toBe('Alice')
      83 |   })
      84 | 

      at Object._id (src/__tests__/datasource.test.js:81:48)

  ● Mongoose › collection

    TypeError: Cannot read property '_id' of null

      86 |     const users = new Users(userCollection)
      87 |     users.initialize()
    > 88 |     const user = await users.findOneById(alice._id)
         |                                                ^
      89 |     expect(user.name).toBe('Alice')
      90 |   })
      91 | })

      at Object._id (src/__tests__/datasource.test.js:88:48)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       2 failed, 11 passed, 13 total
Snapshots:   0 total
Time:        7.796s
Ran all test suites.

The "test" database has been created successfully, along with the user document in it. This is the generated document

{
    "_id" : ObjectId("5de0d787b957c5900fd8d54a"),
    "name" : "Alice",
    "__v" : 0
}
lorensr commented 4 years ago

Ah, thanks—I fixed the test on latest master

On Fri, Nov 29, 2019 at 3:33 AM Jimi notifications@github.com wrote:

I've run that test, and this is the output

PASS src/tests/cache.test.js

FAIL src/tests/datasource.test.js (7.238s)

● Mongoose › data source

TypeError: Cannot read property '_id' of null

  79 |     const users = new Users(UserModel)

  80 |     users.initialize()

> 81 |     const user = await users.findOneById(alice._id)

     |                                                ^

  82 |     expect(user.name).toBe('Alice')

  83 |   })

  84 |

  at Object._id (src/__tests__/datasource.test.js:81:48)

● Mongoose › collection

TypeError: Cannot read property '_id' of null

  86 |     const users = new Users(userCollection)

  87 |     users.initialize()

> 88 |     const user = await users.findOneById(alice._id)

     |                                                ^

  89 |     expect(user.name).toBe('Alice')

  90 |   })

  91 | })

  at Object._id (src/__tests__/datasource.test.js:88:48)

Test Suites: 1 failed, 1 passed, 2 total

Tests: 2 failed, 11 passed, 13 total

Snapshots: 0 total

Time: 7.796s

Ran all test suites.

The "test" database has been created successfully, along with the user document in it

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/GraphQLGuide/apollo-datasource-mongodb/issues/8?email_source=notifications&email_token=AAB5LGGTSZM6MVUYWUODUM3QWDHV7A5CNFSM4JRVVJH2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFOG2NY#issuecomment-559705399, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB5LGFV2Z3H4KXRXIRBVA3QWDHV7ANCNFSM4JRVVJHQ .

GimignanoF commented 4 years ago

I've run the tests with the latest version and it works, however it still doesn't in my application after updating the package to version 0.2.0 :/ So I guess is something I do wrong, but can't figure out exactly what. In the Apollo configuration I do this

dataSources: () => ({
    productPages: new ProductPageDataSource(ProductPageModel)
  }),

where ProductPageModel is the mongoose model.

And this is the ProductPageDataSource module I import

const { MongoDataSource } = require("apollo-datasource-mongodb");

class ProductPages extends MongoDataSource {
  getProductPage(id) {
    return this.findOneById(id);
  }
}

module.exports = ProductPages;

If I try to console.log the value of this.collection it prints out, so I guess is reading the correct value? :/

lorensr commented 4 years ago

Not sure why, but if you can post a small reproduction repo, I can take a look ☺️