I've the following hapi.js server
const Hapi = require('hapi')
const Mongoose = require('mongoose')
const Wreck = require('wreck');
const server = new Hapi.Server({
"host": "localhost",
"port": 3000
})
Mongoose.connect('mongodb://localhost/myDB', { useNewUrlParser: true })
const BlockModel = Mongoose.model('block', {
height: Number,
size: Number,
time: Number
})
server.route({
method: "GET",
path: "/",
handler: async (request, h) => {
Mongoose.model.blocks.remove({}); //<------This is the part of the code I intend to use to delete the collection
const { res, payload } = await Wreck.get('https://api.url');
let myJson = JSON.parse(payload.toString()).blocks
console.log(myJson)
for (let i = 0; i<myJson.length; i++) {
var block = new BlockModel({ height: myJson[i].height, size: myJson[i].size, time: myJson[i].time });
block.save();
}
console.log(myJson)
return "test"
}
})
server.start();
Point is, it works fine and saves the desired data to my collection, but ofc the database will keep growing if I dont delete the data on each execution. So I intend to implement something similar to
db.blocks.remove({}) //where blocks is my collection
Which works fine in the mongoconsole.
But I cant find how to implement this in the code
You can use the deleteMany operator with an empty filter.
db.collection.deleteMany({})
or with your model:
await BlockModel.deleteMany({})
Empty all collections in a db
const collections = await mongoose.connection.db.collections();
for (let collection of collections) {
await collection.deleteMany({})
}
Related
Simply trying to set a new field to the value of an existing field in the same document without iterating (can do iteration but aggregation pipeline seems more efficient)
The aggrgation expression comes from mongodb aggregation builder and it previews fine there.
Code
const { MongoClient } = require('mongodb');
const agg = [
{
'$match': {}
}, {
'$set': {
'old_price': '$price'
}
}, {}, {}];
const url= '...y';
const client = new MongoClient(url);
async function main() {
const client = await MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
const dbName = 'mongodbVSCodePlaygroundDB';
const collname='test';
const coll = client.db(dbName).collection(collname);
const rset = await coll.updateMany(agg);
console.log(rset);
await client.close();
}
main()
.then(console.log('ok'))
.catch(console.error)
.finally(() => client.close());
ERROR: MongoInvalidArgumentError: Document must be a valid JavaScript object
Occurs at this line:
const rset = await coll.updateMany(agg);
Any pointers on getting this to work?
Tried a number of variations with quotes and square braces
I want to connect to MongoDB and query a collection based on the filter 'category'. From the results, I want to randomly select one of entries, concatenate with another string and print to console. I am a novice at this and can't figure out how to get the results of my query and randomly select one of the entries from the query results.
//Connecting To DB
const mongoose = require('mongoose');
//const { makeCard } = require('./utils/card');
const db = mongoose.connection;
const host = process.env.host;
console.log(host)
const dbupdate = {
useNewUrlParser : true,
useUnifiedTopology : true
};
mongoose.connect(host, dbupdate);
db.on('error', (err) => console.log('Error, DB not connected'));
db.on('connected', () => console.log('connected to mongo'));
db.on('disconnected', () => console.log('Mongo is disconnected'));
db.on('open', () => console.log('Connection Made!'));
const Schema= mongoose.Schema;
const cardSchema = new Schema({
word: String,
visual : String,
category : String
});
const Card = mongoose.model('expressions', cardSchema );
--I want this function to return the results of the query, but it doesn't.
function getWords(ctgry ) {
const result = Card.find({"category" : ctgry },(error,results) => {
return results;
});
};
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min);
};
function getWord( ctgry ) {
const result = getWords( ctgry );
const num = getRandomInt(0,result.length); --this doesn't work
return result[num];
};
console.log("Sample text: " + getWord());
What you seem to be doing here is that you're fetching all the documents from the Card model for a particular category and picking a random one from it, which I wouldn't recommend. Not sure what data you're storing here, but what if your app grows to a point where there are a million documents in your cards collection? You wouldn't fetch them all in memory and pick a random one.
A good practice while using any database is to try to only fetch as much data is required. There's no way to fetch a random document from a query in mongodb from what I know, but there's a way to do this (inspired from this answer which I recommend you read).
async function getRandomWord(ctgry) {
const count = await User.count({
"category": ctgry,
}).exec();
const random = Math.floor(Math.random() * count);
return User.findOne({
"category": ctgry,
}).skip(random).exec();
}
I am creating a blog website where you can create your own blog and update it at anytime. However, I want to add a log-in system so that users can have their own separate blog page. My problem is that I have yet to find a way to use both the login database and the blog database in my website. Right now I am using mongoose to connect to mongodb atlas, is there a way to use something like mongoose.connect for multiple databases?
You just have two different mongoose schemas, one for the blogs and the other for the log in. They will be separated in the database, you don't need to have two separate ones.
Here is an example using mongodb package.
I believe you can use the same logic with Mongoose.
import { Db, MongoClient, MongoError } from "mongodb";
const mongoURIs: MongoDBsInterface = {
global: {
uri: process.env.MONGODB_URI_DEFAULT,
db: process.env.MONGODB_DB_NAME,
},
secondary: {
uri: process.env.MONGODB_URI_DEFAULT,
db: "secondaryDatabaseInTheSameCluster",
},
secondary: {
uri: "secondClusterURI",
db: "anotherDatabase",
},
};
// Connection parameters
const param = {
numberOfRetries: 20,
auto_reconnect: true,
useNewUrlParser: true,
useUnifiedTopology: true,
};
// Function to start multiple databases
export const startDatabases = (): Promise<MongoDBsDetailInterface> => {
return new Promise((resolve) => {
const promises = [];
logger.info("### Connect to MongoDBs");
// Loop into each mongoURIs
for (const lang in mongoURIs) {
if (mongoURIs[lang]) {
promises.push(connectToOneDB(lang, mongoURIs[lang]));
}
}
Promise.all(promises).then((res: MongoDBDetailInterface[]) => {
const dbs: MongoDBsDetailInterface = {};
// tslint:disable-next-line: prefer-for-of
for (let i: number = 0; i < res.length; i++) {
dbs[res[i].lang] = res[i].db;
}
resolve(dbs);
});
});
};
export const connectToOneDB = (
lang: string,
dbValue: MongoDBInterface
): Promise<MongoDBDetailInterface> => {
return new Promise(async (resolve) => {
logger.info(` - Connect to ${lang} in db ${dbValue.db} (${dbValue.uri})`);
// Connect to the db
const client = new MongoClient(dbValue.uri, param);
let db = null;
try {
await client.connect();
db = await client.db(dbValue.db);
} catch (e) {
logger.error(e.message);
client.close();
// you should change that to handle it for your usage
process.exit(1);
}
logger.info(` - Connected to ${lang}`);
return resolve({ lang, db });
});
};
And then you can use
const dbs = await startDatabases();
And put it in your global context.
You then just need to select the collection you want
dbs.global.collection("...")
I want to use MongoDB change streams to watch insertion/updates on a first collection to populate, when a condition is meet,another collection with computed values extracted from the watched collection.
Following Mongodb tutorial, I came to the following results:
require('dotenv').config();
const { MongoClient } = require('mongodb');
const stream = require('stream');
const es = require('event-stream');
async function monitorListingsUsingStreamAPI(client, pipeline = []) {
const collection = client
.db(process.env.MONGO_DB)
.collection(process.env.COLLECTION_TO_MONITOR);
const changeStream = collection.watch(pipeline);
const collection_dest = client
.db(process.env.MONGO_DB)
.collection(process.env.COLLECTION_TO_POPULATE);
changeStream.pipe(
es.map(function (doc, next) {
const { _id, ...data } = doc.fullDocument;
const new_doc = { size: data.samples.length, data };
(async () => {
await collection_dest.insertOne(new_doc, next);
})();
}),
);
}
async function main() {
const uri = process.env.MONGO_DB_URI;
const client = new MongoClient(uri, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
try {
// Connect to the MongoDB cluster
await client.connect();
const pipeline = [
{
$match: {
operationType: 'insert',
'fullDocument.samples': { $size: 3 },
},
},
];
// Monitor new listings using the Stream API
await monitorListingsUsingStreamAPI(client, pipeline);
}
}
Actually it seems to work but I used event-stream to pipe MongoDB change stream into another one where I used an immediately-invoked anonymous async functions to populate the second collection.
I wonder if this approach is correct? How to use transform streams?
The official documentation of the Node.js Driver version 3.6 contains the following example for the .find() method:
const { MongoClient } = require("mongodb");
// Replace the uri string with your MongoDB deployment's connection string.
const uri = "mongodb+srv://<user>:<password>#<cluster-url>?w=majority";
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
const database = client.db("sample_mflix");
const collection = database.collection("movies");
// query for movies that have a runtime less than 15 minutes
const query = { runtime: { $lt: 15 } };
const options = {
// sort returned documents in ascending order by title (A->Z)
sort: { title: 1 },
// Include only the `title` and `imdb` fields in each returned document
projection: { _id: 0, title: 1, imdb: 1 },
};
const cursor = collection.find(query, options);
// print a message if no documents were found
if ((await cursor.count()) === 0) {
console.log("No documents found!");
}
await cursor.forEach(console.dir);
} finally {
await client.close();
}
}
To me this somewhat implies that I would have to create a new connection for each DB request I make.
Is this correct? If not, then what is the best practise to keep the connection alive for various routes?
You can use mongoose to set a connection with your database.
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true});
then you need to define your models which you will use to communicate with your DB in your routes.
const MyModel = mongoose.model('Test', new Schema({ name: String }));
MyModel.findOne(function(error, result) { /* ... */ });
https://mongoosejs.com/docs/connections.html
It's 2022 and I stumbled upon your post because I've been running into the same issue. All the tutorials and guides I've found so far have setups that require reconnecting in order to do anything with the Database.
I found one solution from someone on github, that creates a class to create, save and check if a client connection exist. So, it only recreates a client connection if it doesn't already exist.
const MongoClient = require('mongodb').MongoClient
class MDB {
static async getClient() {
if (this.client) {
return this.client
}
this.client = await MongoClient.connect(this.url);
return this.client
}
}
MDB.url='<your_connection_url>'
app.get('/yourroute', async (req, res) => {
try {
const client = await MDB.getClient()
const db = client.db('your_db')
const collection = db.collection('your_collection');
const results = await collection.find({}).toArray();
res.json(results)
} catch (error) {
console.log('error:', error);
}
})