Use more than one MongoDb collection in a single app - mongodb

I have an app which uses MongoDb and I am connecting to MongoDb by calling MongooseModule.forRoot in replies.module.ts, now I have another module called replies.module.ts and I want to connect to another collection but in the same database, should I use the same method in the new module and just change the collection name? does it won't create a duplicate connection to mongo? what is the best practice for that?
Reviews module: reviews.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Review', schema: ReviewSchema}
])],
controllers: [ReviewsController],
providers: [ReviewsService]
})
Replies module: replies.module.ts
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority',),
MongooseModule.forFeature([{name: 'Replies', schema: RepliesSchema}
])],
controllers: [RepliesController],
providers: [RepliesService]
})

I think you can do what you want by naming your connections:
app.module.ts:
#Module({
imports: [
MongooseModule.forRoot('mongodb+srv://user:password#url/reviews?retryWrites=true&w=majority', { connectionName: 'ReviewsDB' }),
MongooseModule.forRoot('mongodb+srv://user:password#url/replies?retryWrites=true&w=majority', { connectionName: 'RepliesDB' })
]})
export class AppModule implements NestModule {}
Then you can use your models, for examples in dedicatied modules:
review.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Review.name, schema: ReviewSchema }], 'ReviewsDB')
],
providers: [ReviewService],
exports: [ReviewService],
})
export class ReviewModule {}
And the for replies:
reply.module.ts :
#Module({
imports: [
MongooseModule.forFeature([{ name: Reply.name, schema: ReplySchema }], 'RepliesDB')
],
providers: [ReplyService],
exports: [ReplyService],
})
export class ReplyModule {}
Do not forget to set the connection name of the wanted database in your forFeature declaration

Related

MongoDb's change stream in NestJs

I look around on how mongoDb change stream can be implemented in NestJs but so far, i can't find any solution or documentation.
There is a similar way by using Hooks middleware, but this can't be triggered if we change data from external app.
#Module({
imports: [
MongooseModule.forFeatureAsync([
{
name: Cat.name,
imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
const schema = CatsSchema;
schema.post('save', function() {
console.log(
`${configService.get('APP_NAME')}: Hello from post save`,
),
});
return schema;
},
inject: [ConfigService],
},
]),
],
})
export class AppModule {}
I found this document https://www.mongodb.com/docs/manual/changeStreams/ but how can we implement this in NestJs?
Something like this should work. I wasn't able to test this since I don't have a replica set set up.
#Injectable()
export class ChangeStreamService implements OnModuleInit {
constructor(#InjectModel(Schema.name) private schemaModel: Model<SchemaDocument>) {}
onModuleInit() {
this.schemaModel.collection.watch<SchemaDocument>().on('change', (e) => {
console.log(e)
})
}
}

Ionic Capacitor Routing provided by Library not working

My whole application is built as a Library and with RoutingModules and Page.
I have no problem with my Routing as is. But as soon as i open my Capacitor compiled Application in an Emulator and use change Routes for more than one time i cannot use the Back Button.
When i do so my View crashes, mainly the router outlet and i cannot click on anything in the content of my Application. The only working modules are the ones not provided by my router outlet but in the html
library.components.html
<components-header></components-header>
<div [#slide]="getDepth(outlet)">
<router-outlet #outlet="outlet"></router-outlet>
</div>
<components-footer></components-footer>
<components-loading *ngIf="Loading"></components-loading>
library.routing-module.ts
const routes: Routes = [
{
path: 'homepage',
component: HomepageComponent,
data: { animation: 1 }
},
{
path: 'report',
component: ReportComponent,
data: { animation: 2 }
},
{
path: 'settings',
component: SettingsComponent,
data: { animation: 4 }
},
];
#NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
app.module.ts
import { AppComponent } from './app.component'
import { LibraryModule } from 'my-lib'
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
IonicModule.forRoot(),
LibraryModule.forRoot(Environment),
LibraryModule.scan(AppComponent)
],
providers: [
//File,
{
provide: RouteReuseStrategy,
useClass: IonicRouteStrategy
},
],
bootstrap: [AppComponent]
})
export class AppModule { }
it makes no difference if i import the RoutingModule directly inside the Application or only in the Library.

NestJs: Query multiple entities from multiple database

I have mysql_server_1.database1.users
And mysql_server_2.database3.users_revenue
How can I query rows from users
How can I query rows from users_revenue
First, I've already setup the connections:
const mysql1__database1 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
type: configService.get("DASHBOARD_DB_TYPE"),
host: configService.get("DASHBOARD_DB_HOST"),
port: configService.get("DASHBOARD_DB_PORT"),
username: configService.get("DASHBOARD_DB_USER"),
password: configService.get("DASHBOARD_DB_PASSWORD"),
database: configService.get("DASHBOARD_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
// entities: [User],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
const mysql2__database3 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
// entities: [User],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
#Module({
imports: [
mysql1__database1,
mysql2__database3,
StatsModule,
],
controllers: [AppController],
providers: [AppService, StatsService],
})
export class AppModule {}
user.service.ts
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
#Injectable()
export class UserService {
constructor(#InjectRepository(User) private usersRepository: Repository<User>) {}
async findAll(): Promise<User[]> {
return await this.usersRepository.find();
}
}
Then this code return an empty array instead of so many rows exists in my database;
const items = await this.userService.findAll();
--- update ---
I've take a look at the typeorm source code:
https://github.com/nestjs/typeorm/blob/8af34889fa7bf14d7dc5541beef1d5c2b50c2609/lib/common/typeorm.decorators.ts#L13
Then https://docs.nestjs.com/techniques/database#multiple-databases
At this point, you have User and Album entities registered with their own connection. With this setup, you have to tell the TypeOrmModule.forFeature() method and the #InjectRepository() decorator which connection should be used. If you do not pass any connection name, the default connection is used.
So I think it should work?
#InjectRepository(User, 'mysql2_database3')
#Module({
imports: [
TypeOrmModule.forFeature([User], "mysql2_database3"),
],
providers: [UserService],
controllers: [StatsController],
})
export class StatsModule {}
Still got the error:
Please make sure that the argument mysql2_database3Connection at index [0] is available in the TypeOrmModule context.
Thank to #jmc29 on discord, his guide helped
The solution is:
const mysql2__database3 = TypeOrmModule.forRootAsync({
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
add one more line:
const mysql2__database3 = TypeOrmModule.forRootAsync({
name: 'mysql2__database3', // -----> Add this line, it's is required
imports: [ConfigModule],
// #ts-ignore
useFactory: (configService: ConfigService) => ({
name: 'mysql2__database3',
type: configService.get("DASHBOARD2_DB_TYPE"),
host: configService.get("DASHBOARD2_DB_HOST"),
port: configService.get("DASHBOARD2_DB_PORT"),
username: configService.get("DASHBOARD2_DB_USER"),
password: configService.get("DASHBOARD2_DB_PASSWORD"),
database: configService.get("DASHBOARD2_DB_NAME"),
entities: [__dirname + '/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
});
for those who face this problem , this is my solution
AppModule
#Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [
database,
databaseAllo
]
}),
TypeOrmModule.forRootAsync({
useFactory: (configs: ConfigService) => configs.get("db_config"),
inject: [ConfigService],
}),
TypeOrmModule.forRootAsync({
name:"db_allo", <= create connection to my second db
useFactory: (configs: ConfigService) => configs.get("db_config_allo"),
inject: [ConfigService],
}),
AuthModule,
JwtAuthModule
],
controllers: []
})
export class AppModule {}
my project module ( contain table from second db )
#Module({
imports: [
TypeOrmModule.forFeature([AlloMpcTable], "db_allo" <= call connection again),
],
providers: [
AlloRepository
],
exports: [AlloRepository],
controllers: [],
})
export class AlloModule {}
my project repository
#Injectable()
export class AlloRepository extends BaseRepository<AlloMpcTable> {
constructor(
#InjectRepository(AlloMpcTable, "db_allo") <= you need to call connection again
private readonly allo: Repository<AlloMpcTable>,
) {
super(allo)
}
public async Find(id: number): Promise<AlloMpcTable> {
return await this.allo.findOne(id)
}
}
so in your case, you need to call "mysql2_database3" again in your providers: [UserService]

Ionic 3 error 'collapse' is not a known element:

iam trying to create my own component using Ionic 3 i follow this steps
Step 1 - create the component using command line
ionic g component collapse
Step 2 - add within app.module
...
declarations: [
CollapseComponent
],
...
entryComponents: [
CollapseComponent
],
...
Step 3 - Trying to use the tag
collapse
but i have this bug.
I've tried many alternatives and nothing has worked.
collapse.ts file
import { Component } from '#angular/core';
#Component({
selector: 'collapse',
templateUrl: 'collapse.html'
})
export class CollapseComponent {
text: string;
constructor() {
console.log('Hello CollapseComponent Component');
this.text = 'Hello World';
}
}
* component.mudule.ts file
import {NgModule} from '#angular/core';
import {PopoverComponent} from './popover/popover';
import {CollapseComponent} from './collapse/collapse';
import {IonicModule} from "ionic-angular";
#NgModule({
declarations: [
PopoverComponent,
CollapseComponent
],
imports: [
IonicModule,
],
exports: [
PopoverComponent,
CollapseComponent
]
})
export class ComponentsModule {
}
You have to write your component like that :
#Component({
selector: 'collapse',
templateUrl: `<URL>`
})
export class CollapseComponent {
}
By default, component tags have a prefix like app. You can also try <{prefixe}-collapse>.
selector field is the most important

Angular 2: Too many components in a module?

I'm a currently working on a sign up forms, which has multiple steps and various conditional forms depending on the account type. The module has almost 30 components (a mix of children and parent components) and all of these are imported into the module file. This is making the entire Angular 2 site run really slow, especially after navigating to the sign up forms and then to another route.
Is it possible that there are too many components/service/providers in a module that it's impacting the performance of the site negatively? Is it recommended to break down the multi-step sign up application forms to multiple modules?
import { CommonModule } from '#angular/common';
import { RouterModule } from '#angular/router';
import { NgModule } from '#angular/core';
import { ReactiveFormsModule } from '#angular/forms';
... all the other imports of components/service for this module
export const routes = [{
path: '',
component: parentComponent,
canActivate: [AuthGuard],
resolve: {
someData: someDataResolver
},
children: [
{ path: '', redirectTo: '0', pathMatch: 'full' },
{ path: '0',
component: someComponent1,
resolve: {
someData1: someData1Resolver
}
},
... a bunch more children routes/components
{ path: '20',
component: someComponent20,
resolve: {
someData20: someData1Resolver
}
}
]
}]
#NgModule({
declarations: [ ... ],
entryComponents: [ ... ],
imports: [ ... ],
providers: [ ... ],
})
export default class SampleModule {
static routes = routes
}
Components number in a module matters only on first load time(or page refresh), then they are loaded in memory. Look for issue in other place