I am trying to watch my mongodb. whenever a change occurs I want to apply an action. This is what I have tried
var mongoose = require('mongoose');
//mongoose.connect('mongodb://localhost/test');
mongoose.Promise = global.Promise
mongoose.connect('mongodb://localhost:27017')
mongoose.connection.createCollection('people');
const Person = mongoose.model('Person', new mongoose.Schema({ name: String }));
Person.watch().
on('change', data => console.log(new Date(), data));
console.log(new Date(), 'Inserting doc');
Person.create({ name: 'john doe' });
console.log(new Date(), 'Inserted doc');
But I am getting the following error
node_modules/mongodb/lib/utils.js:132 throw err; ^
MongoError: $changeStream may not be opened on the internal admin database
How can I fix this ?
yes you should, its a good practice. Mongoose requires a connection to a MongoDB database. You can use require() and connect to a locally hosted database with mongoose.
Change streams in MongoDB requires a replica set to function.
According to Mongoose docs:
To connect to a replica set you pass a comma delimited list of hosts to connect to rather than a single host.
mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);
Full example
const { ReplSet } = require('mongodb-topology-manager');
const mongoose = require('mongoose');
run().catch(error => console.error(error));
async function run() {
// Make sure you're using mongoose >= 5.0.0
console.log(new Date(), `mongoose version: ${mongoose.version}`);
await setupReplicaSet();
// Connect to the replica set
const uri = 'mongodb://localhost:31000,localhost:31001,localhost:31002/' +
'test?replicaSet=rs0';
await mongoose.connect(uri);
// For this example, need to explicitly create a collection, otherwise
// you get "MongoError: cannot open $changeStream for non-existent database: test"
await mongoose.connection.createCollection('Person');
// Create a new mongoose model
const personSchema = new mongoose.Schema({
name: String
});
const Person = mongoose.model('Person', personSchema, 'Person');
// Create a change stream. The 'change' event gets emitted when there's a
// change in the database
Person.watch().
on('change', data => console.log(new Date(), data));
// Insert a doc, will trigger the change stream handler above
console.log(new Date(), 'Inserting doc');
await Person.create({ name: 'Axl Rose' });
console.log(new Date(), 'Inserted doc');
}
// Boilerplate to start a new replica set. You can skip this if you already
// have a replica set running locally or in MongoDB Atlas.
async function setupReplicaSet() {
const bind_ip = 'localhost';
// Starts a 3-node replica set on ports 31000, 31001, 31002, replica set
// name is "rs0".
const replSet = new ReplSet('mongod', [
{ options: { port: 31000, dbpath: `${__dirname}/data/db/31000`, bind_ip } },
{ options: { port: 31001, dbpath: `${__dirname}/data/db/31001`, bind_ip } },
{ options: { port: 31002, dbpath: `${__dirname}/data/db/31002`, bind_ip } }
], { replSet: 'rs0' });
// Initialize the replica set
await replSet.purge();
await replSet.start();
console.log(new Date(), 'Replica set started...');
}
Full example excerpted from https://thecodebarbarian.com/stock-price-notifications-with-mongoose-and-mongodb-change-streams
You can’t, change stream cursor is not available on system collections, or any collections in the admin, local, and config databases. You could try configuring your database structure to not be an admin dB.
Mongodb changeStreams doc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With