Giter VIP home page Giter VIP logo

hapi-mongo-models's Introduction

hapi-mongo-models

A hapi plugin for mongo-models.

Build Status Dependency Status devDependency Status peerDependency Status

Install

$ npm install hapi-mongo-models

Server plugin

During plugin registration we connect to MongoDB using the supplied options.

During Hapi's onPreStart server extension point and based on your autoIndex option, we create any indexes defined in the models supplied.

Register

const HapiMongoModels = require('hapi-mongo-models');

const plugin = {
    plugin: HapiMongoModels,
    options: {
        mongodb: {
            connection: {
                uri: 'mongodb://localhost:27017/',
                db: 'hapi-mongo-models-test'
            },
            options: {}
        },
        models: [
            './path/to/customer',
            './path/to/order'
        ],
        autoIndex: false
    }
};

await server.register(plugin);

Plugin options

The options passed to the plugin is an object where:

  • mongodb - is an object where:
    • connection - is an object where:
      • uri - a string representing the connection uri for MongoDB.
      • db - the name of the database.
    • options - an optional object passed to MongoDB's native connect function.
  • autoIndex - a boolean specifying if the plugin should call createIndexes for each model that has a static indexes property. Defaults to true. Typically set to false in production environments.
  • models - an array strings representing the paths to the models (relative to the current working directory or absolute) of where to find the model on disk.

Have a question?

Any issues or questions (no matter how basic), open an issue. Please take the initiative to read relevant documentation and be pro-active with debugging.

Want to contribute?

Contributions are welcome. If you're changing something non-trivial, you may want to submit an issue before creating a large pull request.

Note: This plugin is designed for basic use-cases. If you find yourself needing more, consider using the source as inspiration and create a custom plugin for your app.

License

MIT

Don't forget

What you create with hapi-mongo-models is more important than hapi-mongo-models.

hapi-mongo-models's People

Contributors

blaircooper avatar jedireza avatar maratvmk avatar mshick avatar nickrobillard avatar simon-p-r avatar timoweiss avatar yenbekbay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hapi-mongo-models's Issues

Casting with `_idClass` can throw an exception

In /lib/base-model.js we need to be catching errors thrown when casting values with _idClass and execute the callback with the error.

These lines:

QUESTION: Does this plug-in support associations?

Hi, I'm new to HAPI and need some notion of models in our new project. We come from using SailsJS which offers some notion of Associations with the use of Waterline. Does your plug-in offer us the ability to have associations and specifically the ability to populate an associated child model?

Can't use Mongo Native method Aggregate

If am using aggregate method on my collection it gives me error

ebug: internal, implementation, error
TypeError: Uncaught error: ClientStatus.aggregate is not a function
at server.route.config.pre.method.reply (

server.after

Hi

Just a heads up Hapi 11.0 has removed server.after method.

Thanks
Simon

Hooks support

This looks like just the project I was looking for. Joi is awesome and it's great that you're using that.

Do you support pre and post hooks? I couldn't find any references to that in the docs. If not, is it anywhere on the roadmap?

BaseModel's cursor not being released.

Hi,
I am using this great library on production and it worked perfectly until a few days ago.
To put it simple, after some usage of the API (vary between 5 min to 20 hours), the BaseModel (hapi-mongo-models) simply timeouts on every request (that is - the callback function is not called - not even as an error).
However, if during its "stuck" mode I evaluate a JS expression (with eval) that creates a brand new mongoDB proxy (using the native 'mongodb'), it works perfectly fine (hence I think it has to do with BaseModel and the fact it is a singleton-ish).
This lead me to believe that the db's cursor itself is not being released properly.
**** The following is an assumption (based on some local code).
I have drilled down to the cursor.js file (part of the native library) and the issue seem to be around the nextObject (line 647, [email protected]), where no object nor error is being captured by the document and it seem to be entering some deadlock.
Unfortunately I can't easily reproduce it.
Any help, debugging, ideas are welcomed.

THANKS.

** I've moved to the newest frame version which did not help.
I've also opened a SW case http://stackoverflow.com/questions/37371421/hapijs-hapi-mongo-models-server-stuck-on-504-http-error

Aggregation

Hi, I want to use native aggregation methods of the mongodb library, but I can't find the way to use it through hapi-mongo-models.

Is there a way to do that?

how to connect mongodb

I fail to connect mongodb.
when I register plugin,there is no error,but I got

curl: (7) Failed to connect to localhost port 8000: Connection refused

when I comment it,it's okay.

updateOne with positional $ operator

I have a document with the following format:

"_id": ObjectId("234345345"),
"name": "My name",
"friends": [
    {
       "id" : ObjectId("2424234234234"),
       "age": 23,
       "teams" : ["team 1", "team 2", "team 3"]
    },
    {
       "id" : ObjectId("1122334455"),
       "age": 28,
       "teams" : ["team 4", "team 5", "team 6"]
    } 
]

I am attempting to update one object in the friends array using the "updateOne" method.

MyModel.updateOne({_id: ObjectID(id), "friends.id": ObjectID(friendId)},{$set: {"friends.$": friendObject} }, function (err,myModel){...}).

However, nothing is being updated. Is this an issue with the UpdateOne function or am I missing something?

If connection.db is optional, why is there an assertion error if it isn't provided?

According to jedireza/mongo-models#39, connection.db is optional. I have observed that it is indeed optional and works as expected without db when uri contains the db name.

However, hapi-mongo-models still contains this line which throws an error if connection.db is not provided:

Hoek.assert(options.mongodb.connection.db, 'options.mongodb.connection.db is required');

Which throws this error if db is undefined or null:

Catch error on server start. Process will terminate now. { AssertionError [ERR_ASSERTION]: options.mongodb.connection.db is required
    at new AssertionError (internal/assert.js:269:11)

I see that options.mongodb.connection is just passed through to mongo-models which means that db should also be considered optional in hapi-mongo-models. Am I missing something? Can we just remove the above assertion in hapi-mongo-models?

using aggregate function

Hey @jedireza I am unable to relate the the example in #15 (As you mentioned in #21 ) with how to use an aggregate method for models. Our app has custom models extended from BaseModel itself, but there seems to be no aggregate function within it. Help is much appreciated, thank you 🙏

Not expected results in v6.0.0 responses

So far, plugin is already registered:

// AdminModel.js

var Admin = require('hapi-mongo-models').MongoModels;

Admin.indexes = [{
  key: {
    username: 1
  },
  unique: true
}, {
  key: {
    email: 1
  },
  unique: true
}];

Admin.collection = 'admins';

Admin.schema = validation;

Admin.findByUsername = function(username, callback) {
  var filter = {};
  this.find(filter, callback);
};
// other.js

var admin = require('AdminModel');

admin.findByUsername('someUser', function(err, res) {
  console.log(res);
});

And the result is:

MongoModels {
  _id: 58490c05aa6bbf587f55951d,
  username: 'someUser',
  password: '123456',
  user_type: 'admin' }

I have updated from v5.0.1 to v6.0.0 and fixed the breaking changes but with no luck. Pretty sure that i'm doing something wrong but can't figure out what it is.

use `createIndexes` instead

ensureIndex is being depricated:
http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#ensureIndex

We should use createIndexes instead:
http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndexes

Docs for the indexSpecs argument can be found here:
http://docs.mongodb.org/manual/reference/command/createIndexes/

We should:

  • Remove ensureIndexes and ensureIndex from BaseModel
  • Remove docs related to ensureIndexes and ensureIndex
  • Create a proxy method for createIndexes in BaseModel that accepts indexSpecs as an argument or looks at the static property on the model (like it is today).
  • Add docs for the createIndexes function

Migration help

Earlier version of hapi-mongo-models had quite good examples (been using it for years), now when "forced" to migration to hapi17.6, I find myself headbanging with current release of hapi-mongo-models, special the limited information and lack of examples...

Does their exists more examples for hapi somewhere I can't find?

$elemMatch returns all subjects

Not sure where the issues arise from, but

e.g In a document I have stored an array with 100 card objects, I only desire to pull one card with id:20 from that document

From console 3.6, this do exactly that:
db.myCards.findOne({ user_id: x }, { cards: { $elemMatch: { id: 20 }}} );

But, from latest hapi-mongo-models, same line will return all cards in the array

Validation

Hi

Where does the joi validation occur? I can see the function created in base model class but can't see where it is used?

Thanks
Simon

Unable to get the instantiated db reference.

Refer the log

Uncaught error: Cannot read property 'collection' of undefined, stack: TypeError: Uncaught error: Cannot read property 'collection' of undefined.

TypeError: Uncaught error: Cannot read property 'collection' of undefined
< at Function.insertOne (/Users/mohitmehta/Documents/repository/server/src/albums/node_modules/mongo-models/index.js:449:42)
< at Function.create (/Users/mohitmehta/Documents/repository/server/src/albums/models.js:15:12)

The complete log is:
< 170811/052500.156, [error] message: Uncaught error: Cannot read property 'collection' of undefined, stack: TypeError: Uncaught error: Cannot read property 'collection' of undefined
< at Function.insertOne (/Users/mohitmehta/Documents/repository/server/src/albums/node_modules/mongo-models/index.js:449:42)
< at Function.create (/Users/mohitmehta/Documents/repository/server/src/albums/models.js:15:12)
< at Controller.albums (/Users/mohitmehta/Documents/repository/node_modules/hapi-albums-api/controllers.js:22:15)
< at Object.internals.handler (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:101:51)
< at request._protect.run (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:32:23)
< at internals.Protect.run (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/protect.js:60:12)
< at exports.execute (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:26:22)
< at each (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/request.js:416:16)
< at iterate (/Users/mohitmehta/Documents/repository/node_modules/items/lib/index.js:36:13)
< at done (/Users/mohitmehta/Documents/repository/node_modules/items/lib/index.js:28:25)
< Debug: internal, implementation, error
< TypeError: Uncaught error: Cannot read property 'collection' of undefined
< at Function.insertOne (/Users/mohitmehta/Documents/repository/server/src/albums/node_modules/mongo-models/index.js:449:42)
< at Function.create (/Users/mohitmehta/Documents/repository/server/src/albums/models.js:15:12)
< at Controller.albums (/Users/mohitmehta/Documents/repository/node_modules/hapi-albums-api/controllers.js:22:15)
< at Object.internals.handler (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:101:51)
< at request._protect.run (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:32:23)
< at internals.Protect.run (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/protect.js:60:12)
< at exports.execute (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/handler.js:26:22)
< at each (/Users/mohitmehta/Documents/repository/node_modules/hapi/lib/request.js:416:16)
< at iterate (/Users/mohitmehta/Documents/repository/node_modules/items/lib/index.js:36:13)
< at done (/Users/mohitmehta/Documents/repository/node_modules/items/lib/index.js:28:25)
< 170811/052500.156, [response] http://127.0.0.1:3000: get /api/v1/albums {} 500 (9573ms)

v6.0.0 release notes

General

We've split the BaseModel out into it's own repo, which makes it a more general tool outside of hapi applications. We're now exclusively using es6 classes instead of using the ampersand-class-extend hack.

Breaking changes

  • BaseModel has moved into it's own package mongo-models. It is also referred to as MongoModels instead of BaseModel.
  • mongo-models is a new peerDepdendency you'll need to include in your application's package.json.
  • BaseModel.extend(...) is gone. Simply extend with es6 class Customer extends MongoModels {}
  • The _collection property has been renamed to collection. Ex: Customer._collection = 'customers'; will now be Customer.collection = 'customers';.
  • BaseModel.connect(options, callback) arguments have changed to MongoModels.connect(uri, options, callback)
  • The options passed to the plugin have a minor change. The url property is now uri.

required() doesn't seem to work...

I got below document schema. However, I can still insert document without some keys....
shouldn't that the required property declare some field that cannot be ignore?
or do I misuse the Joi class?

PrimaryAccount.schema = Joi.object().keys({ // token type
  _id: Joi.object(),
  type: Joi.string().required(),
  credit_card: Joi.object().keys({
    type: Joi.string().required(),
    cardholder_name: Joi.string().required(),
    card_number: Joi.string().creditCard().required(),
    exp_date: Joi.date().format('MMYY'),
    cvv: Joi.string().required()
  }),
  token: Joi.object().keys({
    value: Joi.string().required(),
    exp_date: Joi.date().format('MMYY').required()
  })
}).required();

Plugin example for 7.x.x?

I can find plugin example for hapi-mongo-models 6.x (via source history), but can't seems to find anything for 7, did you neglect this?

set value of a model's property to unique

I have two questions relative to this issue.

How can I set certain property value of a model to unique?

for example: if I have below schema, SurrogateData collection will store 'san' which is a value being used to replace pan (real credit card number according to EMVCo spec.). The san itself should not be duplicated!

SurrogateData.schema = Joi.object().keys({
  _id: Joi.object(),
  san: Joi.string().regex(/^\d{16}/).length(16).required(),
  expr: Joi.string().regex(/\d{4}/).length(4).required(),
  // ManyToOne
  primary_data: Joi.object().keys({
    id: Joi.string().required(),
    pan: Joi.string().regex(/\d{13,19}/).required()
  }).required()
}).required();

Is it correct to use below technique to achieve this?

SurrogateData.indexes = [
    [{ san: 1 }]
];
What's the best strategy under this context to generate a non-duplicated san and insert into collection? Now, I do the following steps:

a. generateSan()
b. checkDuplicated() (if duplicated then go to step a)
c. insert()

Issue with updateOne & update Many

It seems that for some reason we are unable to update a model. No issues with creating, finding, etc.

Using something as simple as the following code, yields a count = 0:

Company.updateOne({ _id: '57c9a2894160eb694371d69d' }, { $set: { name: 'TEST' } }, (err, count) => {
      if(err){
        return reply(Boom.wrap(err, 500));
      }

      reply({ count: count });
    }); 

Is there something that is being overlooked here? I've also looked at the test code and everything seems to be lined up correctly.

arguments optimization

I noticed that you often use

 var args = Array.prototype.slice.call(arguments);

According to this docs it prevents optimization of such function.

Btw very cool project, I was missing something between native-mongodb and mongoose and ideally with Joi validation :-).

Request payload validation

Instead of explicitly calling validate inside the handler itself, do you approve of something like this to validate the payload to a Kitten handler:

server.route({
    method: 'POST',
    path: '/kittens',
    config: {
        validate: {
            payload: Kitten.schema
        }
    },
    handler: function (request, reply) {

        Kitten.create(request.payload, function (err, kitten) {

            if (err) {
                return reply(err);
            }

            reply(kitten);
        });
    }
});

I have a feeling I'm bringing up something very obvious and silly, but I haven't seen this pattern in the examples (yet). This may be a nice way to validate without repetition and returns useful error codes at the route level itself, if you won't be doing much else inside Kitten.validate().

max insert set to 1000

I'm not sure if this was something you did when you made the hapi-mongo-models but you cannot insert more than 1000 length array of documents into a mongo db with your calls. I also wanted to make you aware that this plugin is running on an extremely old version of mongodb version 1.4 i believe and the current version is 2.0.25. This might be the root of the issue.

Updating an array element in a document?

I'm trying to use the positional operator but this doesn't seem to work. Any help appreciated!

var update = {
  $inc: {
    resellers.$.inventory: 1
  }
};

Product.findOneAndUpdate({_id : 1234,'resellers._id': 'zxcv'}, update, function (err, product) {

  if (err) {
    reply(err);
  }

  reply(product);
});

//_id: 1234,
//product: "ShamWow Blue Edition",
//resellers: [
//    {
//       _id : zxcv,
//       inventory: 23
//    },
//    {
//      _id: asdf,
//      inventory: 51
//    } ,
//    (etc)
//]

Boom errors

I'm opening this to gauge support for having hapi-mongo-models return Booms instead of the raw error objects from the native driver. I'd be happy to open a PR if this is something anyone else is interested in. Thoughts?

Promises

Have you considered returning Promises? I have found Promises very handy when dealing with db layer. It usually results in cleaner, more obvious code (imho).

Not authorized on dbname to execute command

If I try to find multiple registries inside an async.each loop, just sometimes, I get Not authorized on dbname to execute command. If it's a security issue I should get the "Not authorized" error always but this is not the case. On the other side, I'm connecting to a vps and if I disable auth=true from Mongo on the server it works correctly.

model.js

async.each(result, function(order, next) {
  AnotherModel.findOne({shop_id: shopId}, function(err, shop) {
    // Sometimes I get err, otherwise the registry
  });
});

Any help ? Thanks

Add distinct method

Hi, I was wondering if you had plans to add a .distinct method, which is available in mongodb's native driver. Thanks!

server.start() to include Mongo models?

Would something like this be possible to call from server.start()?

const server = new Hapi.Server();
...
server.start( function() {
    const Game = server.plugins['hapi-mongo-models'].Game;

    Game.find( {}, function( err, result ) {
        console.log( result );
    });
});

Error:
.../node_modules/hapi-mongo-models/lib/base-model.js:259
const collection = BaseModel.db.collection(this._collection);
^

TypeError: Cannot read property 'collection' of undefined

$set not recognized by updateOne()?

I'm working on an application that uses hapi-mongo-models for its CRUD operations, and I want to update a document with some nested subdocuments. In vanilla Mongo I'd query by _id to find the doc I want to update, and pass a {$set:{}} object as my update, but for some reason I can't get it to update my document (doesn't return as error, just resolves without performing any updates). The same query runs properly in a mongo shell environment.

Is $set not supported by hapi-mongo-models?

Thanks!
Chris

find (Many)

The following query does always return an empty array

Model.find( { '_id': { $in: [ '4ed3ede8844f0f351100000c', '4ed3f117a844e0471100000d' ] }} );

models "path/to/customer" might be off?

Migrating from Hapi 14 to 17.6, any idea why below isn't working?

Doesn't work:
models: [
'./models/user'
],

Works:
models: [
'/home/Hapi17/models/user'
],

Hapi v17 support

Will this plugin be supported in hapi v17? It's listed as an official plugin in the hapi website.

Query ISODate

I have a document in my collection

"created_date" : ISODate("2016-05-20T04:44:08.492Z")

and when I query it from Robomongo using

find({"created_date": new Date("2016-05-20T04:44:08.492Z")}) it works ok.

When I do it from my hapi model I get zero results:

  filter.created_date = new Date("2016-05-20T04:44:08.492Z");

  this.find(filter, function(err, res) {
    console.log("res", res); // Empty Array here!
  });

Am I missing something or is it a bug? Thanks!

Cannot read property 'collection' of undefined

Hi, I'm trying to test with Lab an API that uses hapi-mongo-models but I'm having an error:

Debug: internal, implementation, error 
    TypeError: Uncaught error: Cannot read property 'collection' of undefined
    at Function.BaseModel.insertOne (/home/james/.../node_modules/hapi-mongo-models/lib/base-model.js:423:34)
    at Function.Endpoint.create (/home/james/.../models/endpoint.js:32:92)
    at server.route.handler (/home/james/.../server.js:134:90)
    at Object.internals.handler (/home/james/.../node_modules/hapi/lib/handler.js:94:36)
    at /home/james/.../node_modules/hapi/lib/handler.js:28:23
    at internals.Protect.run (/home/james/.../node_modules/hapi/lib/protect.js:56:5)
    at exports.execute (/home/james/.../node_modules/hapi/lib/handler.js:22:22)
    at /home/james/.../node_modules/hapi/lib/request.js:371:13
    at iterate (/home/james/.../node_modules/hapi/node_modules/items/lib/index.js:35:13)
    at done (/home/james/.../node_modules/hapi/node_modules/items/lib/index.js:27:25)
    at /home/james/.../node_modules/hapi/node_modules/hoek/lib/index.js:841:22
    at process._tickDomainCallback (node.js:381:11)

Test file:

var Lab = require('lab');
var Code = require('code');
var server = require("../");

var lab = exports.lab = Lab.script();
var expect = Code.expect;


lab.experiment("Endpoint", function() {
  lab.test("creation", function(done) {
    var options = {
      method: "POST",
      url: "/api",
      payload: {
        email: '[email protected]'
      }
    };

    server.inject(options, function(response) {
      var result = response.result;

      expect(response.statusCode).to.equal(200);
      expect(result).to.be.an.object();

      done();
    });
  });
});

server.js

...

handler: function (request, reply) {
    var Endpoint = request.server.plugins['hapi-mongo-models'].Endpoint;
    var data = request.payload;

    Endpoint.create(data, function (err, res) {

      if (err) {
        return reply(err);
      }

      reply(res[0]);
    });
  }

...

models/endpoint.js

...

Endpoint.create = function (data, callback) {
  data.date = new Date();

  this.insertOne(data, callback);
};

...

The error says that there is no collection property because BaseModel.db is undefined in:

BaseModel.insertOne = function () {
...

    var collection = BaseModel.db.collection(this._collection);

...
};

So I think I need to connect to the database first but I'm not sure about how to do it. Do you have any suggestions?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.