Cannot use Collection as Model PhalconPHP - mongodb

I'm trying to setup MongoDB collection for my PhalconPHP application.
I have the mongo and collectionManager set up.
$di->set('collectionManager', function(){
return new Phalcon\Mvc\Collection\Manager();
}, true);
//MongoDB Database
$di->set('mongo', function() {
$mongo = new MongoClient("localhost:27017");
return $mongo->selectDb("test");
}, true);
I have a model
class User extends \Phalcon\Mvc\Collection {
....
}
Then I got this error
Unexpected value type: expected object implementing Phalcon\Mvc\ModelInterface, object of type MyApp\Models\User given

Disclaimer: This was extracted from the question.
I was using Model validation instead Validation in the model body.

Related

Change Typegoose collection name after initialize

I am using typegoose to create models. During creation of model, I found that it is possible to provide collection name. But once it is assigned, I am not able to find way to modify it.
export const MyModel: ModelType<MyModel> = new MyModel().setModelForClass(MyModel, {
existingMongoose: mongoose,
schemaOptions: {collection: 'my_collection_name'}
});
So in above MyModel, I want to change collection name where I am importing.
How can I change a collection name in model? Or am I only left with the option of creating this model where I want to use it?
Never mind. I just had to make function of exported object. So I changed it to below, so that I can pass collectionName where I am consuming this model.
const DocumentFieldBooleanValueModel = (collectionName: string) : ReturnModelType<typeof DocumentFieldBooleanValue, BeAnObject> => {
return getModelForClass(DocumentFieldBooleanValue, {
schemaOptions: { collection: collectionName },
});
};
export { DocumentFieldBooleanValueModel };
So now above exported model function I can use as below.
DocumentFieldBooleanValueModel('MyCustomCollectionName')
And it will give same typegoose model.

Mongoose Querying Views

I'm currently using mongoose v. 5.25, against mongoDB v.3.6.
My application is supposed to query data from many different views, for instance, a view I currently have at my DB: db.joboffers_view.find()
will return many records that have been aggregated from different collections.
For a normal collection model, I query it like so:
const model = db.model(attribute);
/*where attribute, can be any registered schema */
model.find().
then((result) => {
resolve(result);
}).
catch((err) => {
reject(err);
});
Then way I register my models is something like this (simplified code):
//...
//abstracting boring connection methods
const db = mongoose.connection
//...
//simple model schema
const users_schema = {
_id: ObjectId,
another_field: String
};
//here I'm registering a schema for a VIEW, instead of normal collection
const view_schema = {
_id: ObjectId,
another_field: String
};
//...
//then
db.model('users', users_schema);
db.model('view', view_schema);
When I run a query from any of my registered models, I get the results just fine. However, when I run it against a model that represents a view on my mongo database, it returns an empty array.
No errors, no nothing, just an empty array.
I have looked through mongoose documentation, and I didn't find any specific method or pattern for querying a view, instead of a collection data.
It seems to be the same way I would do for any other collection I have in my system.
Am I missing something?
I also faced the same issue and figured out the problem is that mongoose, by default, reads collection names by pluralizing the model/view name.
So when you create any view and want to use it in mongoose, either make sure your view name is plural (add s to end of view name) or pass a collection name when initializing a schema.
Example
const users_schema = {
_id: ObjectId,
another_field: String
};
mongoose.model('vw_user_info', users_schema, 'vw_user_info');
I have same problem, but i solved it, please check the name of the view in mongodb, it must be same with db.model('view_name', view_schema);
You can open Mongoose debug by config like this mongoose.set('debug', true);
Add 3rd argument
db.model('view', view_schema, 'view_name_in_db')

Create temp sails model

For unit test I need to create temp model object without saving it in DB, just to have some instance method.
Example of model structure
//User.js - my model
module.exports = {
attributes: {
firstName : { type: 'string' },
lastName : { type: 'string' },
getName: function () {
return this.firstName + ':' + this.lastName;
}
}
};
I have next object
const testData = {
firstName: 'Foo',
lastName: 'Bar'
};
This line creates new record in db
User.create(testData);
Is it possible to avoid record creation? How can I do it?
To answer your initial question, functionality to switch off or on whether Sails actually creates a record in your database when you call Model.create() to the best of my knowledge does not exist, without a workaround as you have or I have described in the comments.
With that said, Sails does offer a simple solution for testing and development purposes.
As a convenience during development, Sails provides a built-in database adapter called sails-disk. This adapter simulates a real database by reading and writing database records to a JSON file on your computer's hard drive.
If you are using a Sails version of < v1 see documentation:
Add a connection to the database in config/connection.js
localDiskDb: {
adapter: 'sails-disk'
},
In the model you are testing, point the model towards the sails-disk connection.
...
module.exports = {
connection: "localDiskDb",
attributes: {
...
If you are using Sails version >= v1 see documentation:
Instead, add sails-disk as a datastore in config/datastores.js
localDiskDb: {
adapter: 'sails-disk'
},
And in the model you are testing, as above, point the model towards the sails-disk datastore.
...
datastore: 'localDiskDb',
...

GraphQL check for unique record on mutation

On a GraphQL mutation, how can I check in the resolve function if the record I´m trying to create is unique ?
Consider the code:
const createUser = {
type: UserType,
description: 'Creates an user',
args: {
data: {
name: 'user',
type: new GraphQLNonNull(UserInputType)
}
},
resolve(root, args) {
let data = args.data;
UserModel.findByName(data.name);
??? How can I return an error here if there is a user with
??? the given name already stored in database ?
const model = new UserModel(data);
model.save();
}
}
Should I keep that logic on the GraphQL Server or should I leave it to the database layer. If I leave it to the database layer, how can I return the database error to my client, so that he knows he´s trying to create an invalid user ?
I´m the following stack: MongoDB, express, Mongoose, graphql-js on server, ReactJS and Relay on client.

Meteor returning a field from MongoDB works in console but not in application

I am trying to read out a file in my MongoDB database. In the console the response is correct while in my application I get the following error:
Uncaught TypeError: Cannot read property 'iati' of undefined
I defined a template helper which should return a certain sub-field within my MongoDB collection. However the following does not seem to work (I get the beforementioned error).
Template.hello.helpers({
test: function() {
return Test.findOne().iati;
}
});
What does seem to work is to return the entire object:
Template.hello.helpers({
test: function() {
return Test.findOne();
}
});
And then call the specific field within the template:
{{test.iati}}
However, I want to use the data within the JavaScript script. What am I doing wrong?
Collection methods like Tests.findOne() return the documents that are already fetched to the client's Minimongo copy. Before your document is fetched, findOne() will return null.
To safeguard against this, simply check the result in the helper before you proceed with the calculation:
Template.hello.helpers({
test: function() {
if(! Test.findOne()) return;
return Test.findOne().iati;
},
});
You can also wait for the subscription in the Iron Router to ensure the proper documents are loaded:
this.route('routeName', {
...
onBeforeAction: function() {
this.subscribe('subscriptionName').wait();
...
},
...
});