how to resolve typescript issue with mongodb - mongodb

I have an issue with this code
const doc = await req.db
.collection('clients')
.find({}, { lName: 1, fName: 1, id: 1 })
giving the typescript error
Type error: Argument of type '{ lName: number; fName: number; id: number; }' is not assignable to parameter of type 'FindOneOptions<any>'.
how can I fix this? thanks!

Solution
This should resolve it for you:
const doc = await req.db
.collection<Client>('clients')
.find({ lName: "", fName: "", id: 1 })
Explaination
The .find() method of Db takes one or two options, where the first option is the FilterQuery and the second is FindOneOptions.
find<T = TSchema>(query?: FilterQuery<TSchema>): Cursor<T>;
find<T = TSchema>(query: FilterQuery<TSchema>, options?: FindOneOptions<T extends TSchema ? TSchema : T>): Cursor<T>;
The options for the second argument are things like sort and limit, not the object to find. What you have in the second argument is the FilterQuery which needs to be the first argument.
The FilterQuery type is generic, so in order for typescript to know that we are filtering clients, we need to pass the generic when calling collection<Client>('clients'). That will cause it to return a collection of Client.
This is the interface I used, but I'm sure there are more properties
interface Client {
lName: string;
fName: string;
id: number;
}
Now, if you pass an invalid type to .find(), typescript knows and will throw and error.
.find({ lName: 1, fName: 1, id: 1 })
This is now an error because I said that fName and lName must be string.
Typescript Playground Link

Related

Typegoose and Mongoose - Cast to ObjectId failed for value when saving nested list of schema types

Getting this error:
Competition validation failed: results.0: Cast to ObjectId failed for value "{ name: 'David'}"
Here's the parent:
class Competition {
#prop()
compName: string
#prop({ ref: () => CompetitionParticipant})
results: Ref<CompetitionParticipant>[]
}
Here's the child:
class CompetitionParticipant {
#prop()
name: string
}
Here's how it's being called:
const CompetitionResults = getModelForClass(Competition)
await new CompetitionResults({compName: 'competition name', results: [{name: 'David'}]}).save()
this is because you try to save value { name: 'David' } as an reference, which is not supported (read here for more), you need to either provide and valid _id (in this case an ObjectId), or an instance of mongoose.Document
the easiest workaround is to manually loop over the array and save them individually (like in an bulk-insert call, or in an for loop over the array)

Unable to insert array data into mongodb using mongoose

I am trying to insert data into my mongodb database. I am using mern stack.
This is my user model for the city data that is in array containing city_name & city_code
city: [{
city_name: {type: String},
city_code: {type: String},
}],
I am passing the values to the register function in this manner
city: [{city_name: this.state.c_name, city_code: this.state.c_code}],
This is the function defined to register into the database
city: [{ city_name: req.body.c_name, city_code: req.body.c_code}],
No error's message is being returned in the console. I am using a message where if the user is registered successfully it returns User Registered or else the error message. But I am not getting anything in the console.
Constructor defined in the front end side to get the values
city: [{city_name: '', city_code: ''}],
UPDATED
This is the function I am using to post the data
export const register = newUser => {
return axios
.post('users/sign-up', {
username: newUser.username,
email: newUser.email,
phone: newUser.phone,
dob: newUser.dob,
city: [{city_name: newUser.c_name, city_code: newUser.c_code}],
password: newUser.password
})
.then(response => {
console.log('Registered')
})
}
SOLUTION
So whenever you are accessing the data stored in array we need to give the index value.
<td>{this.props.obj.city[0].cityname}</td>
<td>{this.props.obj.city[0].citycode}</td>

Typescript & MongoDB type erasing when adding methods to the schema

I've been playing around with typescript and mongodb for the past few days and I wanted to add a custom method which I can execute on Document instances. Here is my setup:
import { Document, Schema, model, Model } from "mongoose";
import { AlbumSchema, AlbumDocument } from './album';
And here is my Document interface:
interface ArtistDocument extends Document {
name: string;
identifier: string;
albums: [AlbumDocument];
testFunction(): string
}
And my Schema:
const ArtistSchema = new Schema({
name: {type: String, required: true},
identifier: {type: String, required: true},
albums: {type: [AlbumSchema], required: true, default: []}
});
ArtistSchema.methods.testFunction = function(): string {
return "Hello World";
}
Note that I can just call testFunction(); on an instance of Artist just fine. So I know that methods are working.
Here is the issue though:
ArtistSchema.methods.testFunction = function(): string {
return "Albums:" + this.albums.length;
}
this.albums (which should be of type AlbumDocument[]) is somehow type any and therefore I can not use any array builtin functions nor can I filter and have AlbumDocument available to use its properties.
Is there anything that I am doing wrong? Is there a fix for it?
Try to instanciate albums like so :
albums:new Array<AlbumDocument>();

Associated Data Not Returned From Apollo to Client?

Here's relevant Apollo code. (Many database fields have been omitted to make it faster/easier to read this post.)
CONNECTORS
const userAccountsDataModel = db.define('userAccountsData', {
id: {type: Sequelize.STRING, primaryKey: true},
picture_medium: {type: Sequelize.STRING}
});
const associatesDataModel = db.define('associatesData', {
_id: {type: Sequelize.STRING, primaryKey: true},
first_name: {type: Sequelize.STRING},
last_name: {type: Sequelize.STRING},
userID: {type: Sequelize.STRING},
});
associatesDataModel.belongsTo(userAccountsDataModel, {foreignKey: 'userID'});
SCHEMA
type userAccountsData {
id: String
picture_medium: String
}
type associatesData {
_id: String
first_name: String
last_name: String
userID: String
userAccountsData: [userAccountsData]
}
QUERY
const GETONEASSOCIATE_QUERY = gql`
query getOneAssociate($_id: String!) {
getOneAssociate(_id: $_id) {
_id
first_name
last_name
userID
accountsData{
id
picture_medium
}
}
} `;
RESOLVER
getOneAssociate(_, args) {
console.log('in getOneAssociate');
var ret = connectors.associatesData.findAll({
where: args,
include: [connectors.userAccountsData],
logging: console.log
}).then((res) => res.map((item) => item.dataValues));
return ret;
},
Via Sequelize, the resolver generates the following SQL:
SELECT "associatesData"."_id",
"associatesData"."first_name",
"associatesData"."last_name",
"associatesData"."userID",
"userAccountsDatum"."id" AS "userAccountsDatum.id",
"userAccountsDatum"."picture_medium" AS "userAccountsDatum.picture_medium"
FROM "associatesDatas" AS "associatesData"
LEFT OUTER JOIN "userAccountsData" AS "userAccountsDatum"
ON "associatesData"."userID" = "userAccountsDatum"."id"
WHERE "associatesData"."_id" = '35';
When I run the above SQL in my SQL client, I can see that all the data sought is being returned, including the data from the related "userAccountsData" table.
However, when the data gets to my client code running in javascript the browser, the data from the related table is missing-- the object that should contain it is null.
What am I missing?
Thanks in advance to all for any info!
This turned out to be an anomaly with Sequelize's automatic pluralizing of table names.
By default, Sequelize automatically pluralizes table names. It is supposed to be possible to turn this behavior off by using Sequelize's freezeTableName property. However, per this Sequelize issue post, there are cases in which Sequelize ignores the freezeTableName property and pluralizes (and sometimes singularizes) the table names anyway.
After discovering this I was able to resolve the anomaly by pluralizing the relevant table name and going through all my Apollo code to update the references to this table so that they would be pluralized as well.

define authorized values for a Schema's field

Is it possible in Mongoose, to define authorized values for a specific field ?
For example my field "style", would only be allowed to be set to "jazz", "blues" or "rock"
var artistSchema = new mongoose.Schema({
style: {
type: String
// only allow values "jazz", "blues", "rock"
}
});
First of all you are talking about mongoose schema types (String).
You have to know that it is possible to add some options when defining a schema type (options).
According to what you want to do, the option enum seems to be a good choice.
Ps: enum is a built-in validator, what is a validator?
Example from the documentation
var states = 'opening open closing closed'.split(' ')
var s = new Schema({ state: { type: String, enum: states }})
Your case
const CONSTANT_GOOD_VALUES = ['jazz', 'blues', 'rock'];
var artistSchema = new mongoose.Schema({
style: {
type: String
enum: CONSTANT_GOOD_VALUES,
},
});
Try this :-
var artistSchema = new mongoose.Schema({
status: {
type: String,
enum : ['jaz,'blues','rock']
},
});