I am trying to create a time series schema using mongoose in Nestjs. Here's my schema -
import { Prop, Schema, SchemaFactory } from '#nestjs/mongoose';
import { Document } from 'mongoose';
export type NewUserModel = NewUser & Document;
#Schema({
timeseries: {
timeField: 'timeStamp',
metaField: 'Name',
granularity: 'seconds',
},
})
export class NewUser {
#Prop({ required: true })
readonly Name: string;
#Prop({ required: true })
readonly Skills: string;
#Prop({ type: Date })
readonly timeStamp: Date;
}
export const NewUserSchema = SchemaFactory.createForClass(NewUser);
And here's the json request that I am sending through postman -
{
"Name": "Nikolia Mangan",
"Skills": "Management",
"timeStamp": "2022-06-22T06:22:57.606+00:00"
}
This creates a collection but not a time series collection. I can confirm that by running this command in the shell -
db.runCommand( { listCollections: 1.0 } )
Which in turn returns the output -
"type" : "collection",
Related
I've been trying to recover data querying with an include, my first model is "Block" and this has a "hasMany" relation to the destiny model called "Site". Well, usually this works as intended but this time it has a catch, the data is stored in mongodb with ObjectID(), so if I try to query it on robo3t or whereever, I have to put the ObjectId and inside the ID itself of the document.
I found on the loopback 4 documentation that if I'm saving or relating data which is store with objectId, I have to set the property dataType:ObjectId, but still dosnt work.
My Block model:
import {Entity, model, property, hasMany} from '#loopback/repository';
import {Site} from './site.model';
#model({
settings: {
strict: false,
mongodb: {
collection: 'bloques',
},
},
})
export class Block extends Entity {
#property({
type: 'string',
id: true,
defaultFn: 'uuidv4',
mongodb: {dataType: 'ObjectId'},
})
id: string;
#property({
type: 'date',
required: true,
})
dateBlock: string;
#property({
type: 'object',
required: true,
})
statuses: object;
#hasMany(() => Site)
minedIds: Site[];
/* #hasMany(() => Site)
minedIds: Site[];*/
[prop: string]: any;
constructor(data?: Partial<Block>) {
super(data);
}
}
export interface BlockRelations {
// describe navigational properties here
}
export type BlockWithRelations = Block & BlockRelations;
My Site Model:
import {Entity, hasMany, model, property} from '#loopback/repository';
import {CachimbaModel} from './cachimba-model.model';
#model({
settings: {
// model definition goes in here
mongodb: {collection: 'minadas'},
},
})
export class Site extends Entity {
#property({
type: 'string',
id: true,
generated: true,
mongodb: {dataType: 'ObjectId'},
})
id?: string;
#property({
type: 'date',
required: true,
})
lastUpdate: string;
#property({
type: 'string',
required: true,
})
name: string;
#property({
type: 'string',
required: true,
})
logo: string;
#hasMany(() => CachimbaModel)
data: CachimbaModel[];
#property({
type: 'string',
dataType: 'ObjectId',
})
blockId?: string;
constructor(data?: Partial<Site>) {
super(data);
}
}
export interface SiteRelations {
// describe navigational properties here
}
export type SiteWithRelations = Site & SiteRelations;
And their respective repos are as the following:
block-repo
import {Getter, inject} from '#loopback/core';
import {DefaultCrudRepository, repository, HasManyRepositoryFactory} from '#loopback/repository';
import {DbDataSource} from '../datasources';
import {Block, BlockRelations, Site} from '../models';
import {SiteRepository} from './site.repository';
export class BlockRepository extends DefaultCrudRepository<
Block,
typeof Block.prototype.id,
BlockRelations
> {
public readonly minedIds: HasManyRepositoryFactory<Site, typeof Block.prototype.id>;
constructor(
#inject('datasources.DbDataSource') dataSource: DbDataSource,
#repository.getter('SiteRepository')
protected siteRepositoryGetter: Getter<SiteRepository>,
) {
super(Block, dataSource);
this.minedIds = this.createHasManyRepositoryFactoryFor('minedIds', siteRepositoryGetter,);
this.registerInclusionResolver('minedIds', this.minedIds.inclusionResolver);
}
}
site-repo
import {Getter, inject} from '#loopback/core';
import {
DefaultCrudRepository,
HasManyRepositoryFactory,
repository,
} from '#loopback/repository';
import {DbDataSource} from '../datasources';
import {CachimbaModel, Site, SiteRelations} from '../models';
import {CachimbaModelRepository} from './cachimba-model.repository';
export class SiteRepository extends DefaultCrudRepository<
Site,
typeof Site.prototype.id,
SiteRelations
> {
public readonly data: HasManyRepositoryFactory<
CachimbaModel,
typeof Site.prototype.id
>;
constructor(
#inject('datasources.DbDataSource') dataSource: DbDataSource,
#repository.getter('CachimbaModelRepository')
protected cachimbaModelRepositoryGetter: Getter<CachimbaModelRepository>,
) {
super(Site, dataSource);
this.data = this.createHasManyRepositoryFactoryFor(
'data',
cachimbaModelRepositoryGetter,
);
this.registerInclusionResolver('data', this.data.inclusionResolver);
}
}
I try to query and obtain the nested data from the block controller using an include as the following:
And my database has the following values:
I will apreaciate your help for real! Thanks in advance!
My bad, I didnt have to set the ids on minedIds property, I had to set it on the destinatary model property opposite to the hasMany
I want to create a GraphQL API with the following schema
app.use(
"/graphql",
graphQlHttp({
schema: buildSchema(`
type Event {
_id: ID!
title: String!
description: String!
price: Float!
}
input EventInput {
title: String!
description: String!
price: Float!
}
type QueryResolver {
getEvents: [Event!]!
}
type MutationResolver {
createEvent(eventInput: EventInput): [Event!]!
}
schema {
query: QueryResolver
mutation: MutationResolver
}
`),
rootValue: {}
})
);
Currently I am using it as a string in in the my main file. I want to separate it out in a graphql file. One way can be that we can read the file but I think it will not be efficient.
Can you please tell me how can I do this?
You can add this node module:
https://github.com/ardatan/graphql-import-node
Then move your schema to something like mySchema.graphql.
Then, in JS:
const mySchema = require('./mySchema.graphql');
or in TypeScript:
import * as mySchema from './mySchema.graphql';
I don't have the reputation to comment so I'll put this here.
If anyone following #Tim O'Connell's answer is wondering how to pass the imported Schema to BuildSchema(), since it's not a string anymore but a DocumentNode, you actually need to use the function BuildASTSchema().
Note that BuildSchema() is just a wrapper around BuildASTSchema() that parses the given string into a DocumentNode. (source)
So to recap, do something like this :
import 'graphql-import-node';
import { buildASTSchema } from 'graphql';
import * as mySchema from './schema.graphql';
export = buildASTSchema(mySchema);
Just import all of your schemas using the gql module. Install it by:
npm i graphql-tag
You can use the graphql-tool.
const { loadSchemaSync } = require("#graphql-tools/load");
const { GraphQLFileLoader } = require("#graphql-tools/graphql-file-loader");
const { addResolversToSchema } = require("#graphql-tools/schema");
const { join } = require("path");
const schemaWithResolvers = addResolversToSchema({
schema: loadSchemaSync(join(__dirname, "./(your graphql file).graphql"), {
loaders: [new GraphQLFileLoader()],
}),
resolvers: {},
});
And, your graphql file is
type Event {
_id: ID!
title: String!
description: String!
price: Float!
}
input EventInput {
title: String!
description: String!
price: Float!
}
type QueryResolver {
getEvents: [Event!]!
}
type MutationResolver {
createEvent(eventInput: EventInput): [Event!]!
}
schema {
query: QueryResolver
mutation: MutationResolver
}
Then, you just need to use schemaWithResolvers.builldSchema is unnecessary .
app.use(
"/graphql",
graphQlHttp({
schema: schemaWithResolvers
})
);
As a beginner in node js I cannot wrap my head around following problem.
import { createSchema, Type, typedModel } from "ts-mongoose";
const CompanySchema = createSchema(
{
companyName: Type.string({ required: true, unique: true })
},
{
timestamps: true
}
);
const Company = typedModel("Company", CompanySchema);
export { CompanySchema, Company };
This all works just fine until one point. When attempting to import this file.
import {CompanySchema, Company} from "./Company";
It executes typeModel method and stores the schema as expected. However, any other import of this file Company.ts reruns this method typeModel again. Which then fails because I can register schema with the name only once. How could I prevent of reruning this and still keep access to this object?
What would be general approach to this in order to keep access to both CompanySchema and Company object(as they will be later used in another schema as a reference)?
I don't know what the createSchema and typedModel are( if they are functions created by you or part of mongoose, the versions of mongoose ive worked with didnt have these functions )
...but I think you should not "createSchema" but define it instead.
e.g
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// define schema
const messageSchema = Schema({
sender: { type: Schema.Types.ObjectId, ref: 'User' },
recipient: { type: Schema.Types.ObjectId, ref: 'User' },
createdAt: { type: Date, default: Date.now },
deletedAt: { type: Date, default: undefined },
readAt: { type: Date, default: undefined},
message: { type: String, maxlength: 5000 }
});
// create a model based on that schema
const Message = mongoose.model('Message', messageSchema);
// Export the message model ... not the schema
module.exports.Message = Message;
https://loopback.io/doc/en/lb4/HasMany-relation.html
I followed this steps and then tried to get data with include but I get 500.
500 Error: Invalid "filter.include" entries: {"relation":"ranks"}
What I want is to get games object with its related ranks.
Rank Model
import { Entity, model, property, belongsTo } from '#loopback/repository';
import { Game, GameWithRelations } from './game.model';
#model({ settings: { strict: 'filter' } })
export class Rank extends Entity {
#property({
type: 'string',
id: true,
})
id?: string;
#property({
type: 'string',
})
name?: string;
#property({
type: 'string',
})
shortName?: string;
#property({
type: 'string',
})
avatar?: string;
#belongsTo(() => Game)
gameId: string;
constructor(data?: Partial<Rank>) {
super(data);
}
}
export interface RankRelations {
game?: GameWithRelations;
}
export type RankWithRelations = Rank & RankRelations;
Game Model
import { Entity, model, property, embedsMany, hasMany } from '#loopback/repository';
import { Rank, RankWithRelations } from './rank.model';
import { HasMany } from 'loopback-datasource-juggler';
#model({ settings: { strict: 'filter' } })
export class Game extends Entity {
#property({
type: 'string',
id: true,
})
id?: string;
#property({
type: 'string',
required: true,
})
name?: string;
#property({
type: 'string',
})
shortName?: string;
#property({
type: 'string',
})
avatar?: string;
#hasMany<Rank>(() => Rank, { keyTo: 'gameId' })
ranks?: Rank[];
constructor(data?: Partial<Game>) {
super(data);
}
}
export interface GameRelations {
}
export type GameWithRelations = Game & GameRelations;
Game Controller
// in this method
// 500 Error: Invalid "filter.include" entries: {"relation":"ranks"}
#get('/games/{id}')
async findById(#param.path.string('id') id: string): Promise<Game> {
return await this.gameRepository.findById(id, { include: [{ relation: 'ranks' }] });
}
Please run your application with DEBUG=loopback:repository:relation-helpers, that way you will get a debug message explaining why filter.include entry was rejected.
You can find the code building the error message here:
https://github.com/strongloop/loopback-next/blob/97ba7893e253bfc2967ac08e408b211c9b9b7f40/packages/repository/src/relations/relation.helpers.ts#L96-L100
The most likely cause: your GameRepository does not have any InclusionResolver registered for ranks relation.
Please refer to our todo-list example to see how to register inclusion resolver. Cross-posting from https://github.com/strongloop/loopback-next/blob/97ba7893e253bfc2967ac08e408b211c9b9b7f40/examples/todo-list/src/repositories/todo-list.repository.ts#L41-L46:
this.todos = this.createHasManyRepositoryFactoryFor(
'todos',
todoRepositoryGetter,
);
this.registerInclusionResolver('todos', this.todos.inclusionResolver);
I have dug all I can and every "solution" I find is either a mistyped schema name or a missing / misordered require, which I'm quite certain is not what I'm running into.
I am using Typescript 2.6.2, Node 8.9.4, and Mongoose 5.0.2. I have two models. One is for Accounts and one for Organizations. When I run a findOne with a populate against the Accounts model, I get: 'MissingSchemaError: Schema hasn't been registered for model "Organization".'
/src/models/Organization.model.ts
import * as mongoose from 'mongoose';
export type OrganizationModel = mongoose.Document & {
name: string,
suborganizations: [OrganizationModel]
};
const OrganizationSchema = new mongoose.Schema({
name: {type String, required: true},
suborganizations: [
{type: mongoose.Schema.Types.ObjectId, ref: 'Organization'}
]
});
const Organization = mongoose.model<OrganizationModel>('Organization', OrganizationSchema);
export default Organization;
/src/models/Account.model.ts
import * as mongoose from 'mongoose';
import { default as Organization, OrganizationModel } from './Organization.model';
export type AccountModel = mongoose.Document & {
username: string,
organization: OrganizationModel
};
const Account = new mongoose.Schema({
username: {type: String, required: true},
organization: {type: mongoose.Schema.Types.ObjectId, ref: 'Organization'}
});
const Account = mongoose.model<AccountModel>('Account', AccountSchema);
export default Account;
/src/controller/account.ts
import * as mongoose from 'mongoose';
// I've tried without and with the following import
import { default as Organization, OrganizationModel } from '../models/Organization.model';
import { default as Account, AccountModel } from '../models/Account.model';
const AccountManager = {
getAccount: async ({ username }) => {
// Here is the troubled line
const account = await Account.findOne({ username }).populate('organization organization.suborganizations');
return account;
}
};
export default AccountManager
I had the same problem and i guess this happened because your unused import was removed by compiler.
Try import './Organization.model';