Connecting to MongoDB from Vercel - mongodb

I have a SvelteKit application deployed on vercel.app that uses a MongoDB (Atlas). In most cases the database connection works, but sometimes I get a connection error (connection timed out).
If this error occurs, and I try again to do something that uses the database, it immeadiately logs the same error again. This problem persists for some time, and then suddendly the database connection works again.
(When running the app locally with "npm run dev", using the same database, I've never experienced this error.)
To connect to the database, I defined:
mongodb-client.ts:
import { MongoClient } from 'mongodb';
const uri = process.env.DB_URI;
const dbClient = new MongoClient(uri).connect();
export default dbClient;
and use it like this (in several places):
import dbClient from '$lib/server/mongodb-client';
const user = await (await dbClient).db().collection('users').findOne({username: username});
I guess that, when the dbClient Promise is rejected (for whatever reason), it stays rejected and any subsequent await will immediately result in "rejected" (and therefore it will not try to reconnect; except that at some point it will ...?). Is my understanding correct? How should this be implemented correctly? (E.g. Do I need to add some options to the connection URI when this connection is create from a serverless function? Do I need to add some options when creating/connecting the MongoClient? Do I need to do this manually and add a loop, check if the promise is rejected and try again? Or should this be implemented in a completely different way?)
As you probably have guessed I'm new to JavaScript/TypeScript, MongoDB, Serverless and everything ... Thanks for any help and advice!

You can declare a function handling the connection to the database.
You will handle connection errors there and also check if a connection is already established:
import { MongoClient } from 'mongodb';
const uri = process.env.DB_URI;
const dbClient = new MongoClient(uri);
export const connectDb = async () => {
try {
if (!dbClient.isConnected()) {
await dbClient.connect();
}
return await dbClient.db();
} catch (e) {
console.log(e);
process.exit(1); // Or do something else...
}
};
Usage:
import { connectDb } from '$lib/server/mongodb-client';
const db = await connectDb();
const user = await db.collection('users').findOne({username: username});

Related

Insert a user by default in MongoDB in Nest JS (Only when the app starts)

I am changing the project from expressjs to nestjs.
In express, I added an admin user to the database by default in app.ts.
like this:
public async addDefaultAdmin() {
UserModel.find({ role: Roles.admin }).then(async (superAdmin) => {
if (superAdmin.length === 0) {
try {
const newUser = new UserModel({...});
await this.hashPassWord(newUser);
await newUser.save();
console.log("default admin successfully added.");
} catch (error: any) {
console.log(error);
}
}
});
}
I wanted to know how I can do this in NestJS?
Does NestJS or typeOrm have a solution for this issue?
You may need to use lifecycle events. NestJS fires events during application bootstrapping and shutdown.
According to doc, onApplicationBootstrap() event may be helpful in your case.
Called once all modules have been initialized, but before listening for connections.
However, NestJS does not expose a hook after the application starts listening, so in this case you need to run your custom function inside of bootstrap function right after the server could listen to a port.
The pseudocode would be like this:
// main.ts
import { User } from '/path/to/user.entity';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
...
await app.listen(3000);
let user = app.get(getRepositoryToken(User)); // You need to pass the entity file to typeorm
await addDefaultAdmin(user); // Pass the user model, and call the function
}
bootstrap();

How to fetch data from supabase

I tried this by exploring web and supabase docs but nothing really happens
import 'package:supabase/supabase.dart';
class supahandelar {
static const SupaUrl = 'UrlFromSupabase';
static const SupaKey = 'KeyFromSupabase';
final client = SupabaseClient(SupaUrl, SupaKey);
getData() async {
var response = await client.from('Pokemons').select().execute();
print("Respnse");
print(response);
}
}
It gives me this output on console:
instance of 'minified:hy<erased>'
Also not getting any output in widgets/ui
Can anyone please suggest me simple methods to only fetch data.
It was just an RSL issues. When i tried with new databases without RSL disabled it worked.
So i need to create RSL Policy of who to allow read data...
For Ex:-I Added true for all user to read
If anyone face this issue please check/ Create RSL Policy.

How to connect to mongodb database using Nextjs?

Trying to connect to my mongodb database in the latest version of Nextjs. Things have changed so much, so I don't longer know what to do.
There's an example of how to set up the connection here: https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
They use this file:
//The mongodb.js file from the example
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Please add your Mongo URI to .env.local')
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
However, they forgot to add how to actually use it. I can't even begin to figure it out.
//pages/api/user.js
import client from '/lib/mongodb.js'
export default async function handler(req, res) {
//How do I connect here?
}
And two bonus questions:
I used to do caching on my database connection. Is it not needed anymore?
What happened to the utils folder? It used to be special, in that it didn't send anything there to the client. Now everyone seem to use lib but I don't think there's anything special with it?
You can do like this:
const dbClient = await client;
const db = dbClient.db('db-name');
const collection = db.collection('collection-name');
// example to get a doc in collection
const doc = await collection.findOne({query:""}, {...options})

Why does Mongoose setClient return MongooseError: Must call `setClient()` with an instance of MongoClient?

I am having trouble getting setClient() to work. My understanding of this is, that I can make a connection to MongoDB with the native MongoDB MongoClient and then in another piece of code I should be able to use this instance of the MongoClient to connect to Mongoose. So set the client to Mongoose while using the same identical connection, not a separate one.
https://mongoosejs.com/docs/api/connection.html#connection_Connection-setClient
Set the MongoDB driver MongoClient instance that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to reuse it.
Case A
import mongoose from 'mongoose';
import { MongoClient } from 'mongodb';
async function run() {
try {
const uri = 'mongodb://localhost:27017';
// Create a new MongoClient
const client = new MongoClient(uri);
const conn = mongoose.createConnection().setClient(client);
conn.getClient(); // MongoClient { ... }
conn.readyState; // 1, means 'CONNECTED'
} catch (error) {
console.log(error);
}
}
run();
This returns
MongooseError: Must call setClient() with an instance of MongoClient at NativeConnection.setClient (.../node_modules/mongoose/lib/connection.js:1391:11).
Why am I getting this error ? What is the correct code for setClient()?
Case B
Vercel shows how to used MongoDB and Mongoose in their environment exporting a clientPromise here with MongoDB https://github.com/vercel/next.js/blob/canary/examples/with-mongodb/lib/mongodb.js and a dbConnect here with Mongoose https://github.com/vercel/next.js/blob/canary/examples/with-mongodb-mongoose/lib/dbConnect.js.
So given in db.js I have this exemplary code with the native MongoDB driver
import { MongoClient } from 'mongodb'
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise
if (!process.env.MONGODB_URI) {
throw new Error('Please add your Mongo URI to .env.local')
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
and in another file I like to use this clientPromise with Mongoose what do I do ?
Is my understanding correct here that I in fact can use the exported MongoDB clientPromise with Mongoose at all through the use of setClient() ? Or is setClient() used for something different ?
In another file, if I try this
import mongoose from 'mongoose';
import clientPromise from '$lib/mongodb';
export async function get() {
try {
const client = await clientPromise;
console.log(client); // logs client just fine
const conn = mongoose.createConnection().setClient(client);
// starts complaining here with
// MongooseError: Must call `setClient()` with an instance of MongoClient
conn.getClient(); // MongoClient { ... }
conn.readyState; // 1, means 'CONNECTED'
console.log(conn);
return {
status: 200,
body: {
message: 'ok'
}
};
} catch (error) {
console.log(error);
}
}
the same error is shown.
How do I get setClient() to work on either, the MongoClient instance or the clientPromise?
edit:
I also get this error.
Argument of type 'import(".../node_modules/mongodb/mongodb").MongoClient' is not assignable to parameter of type 'import(".../node_modules/mongoose/node_modules/mongodb/mongodb").MongoClient'.
The types of 'options.credentials' are incompatible between these types.
Type 'import(".../node_modules/mongodb/mongodb").MongoCredentials' is not assignable to type 'import(".../node_modules/mongoose/node_modules/mongodb/mongodb").MongoCredentials'.

MongoDB : Current Topology does not support session

I am learning MEAN Stack development. I am trying to execute a transaction.
Steps I followed :
I start the mongod.exe with flag set to --replSet rs0.
Then I start the Mongo Shell.
Then I write following code.
let session: ClientSession | undefined;
try {
const data = req.body;
console.log(data);
const movie = new Movie({ name: data['name'], cast: data['cast'] });
const conn = await db.connect()
session = await conn.startSession()
session.withTransaction(async () => {
const doc = await movie.save({ session: session, validateBeforeSave: true });
SuccessResponse(res);
res.json(doc);
})
await session.commitTransaction()
session.endSession();
} catch (err) {
console.log(err)
await log(err)
if (session) {
//session.abortTransaction();
session.endSession()
}
ServerError(res);
res.end();
}
But I got follwoing error
MongoError: Current topology does not support sessions
Any help.
It seems like if your connection was on a hold (eg. hitting a break point), MongoError: Current topology does not support sessions gets thrown even though Current topology.. part does not have nothing to do with it. Maybe Session connection timed out. Try again would be more appropriate.
So, if you are sure your setup should support sessions, just try again.