I wanna create a hook function when client search any query in database and tried to use Mongo.watch()
Reference code:
mongo.db
.watch([{ $match: { operationType: 'insert' } }])
.on("change", (next) => {
console.log("##", next);
});
It is working when I using .insert() and .update(), as I know that is working for data changed but not for .find().
How can i hook query after find?
I found the solution finally and mark down the code base here.
Mongo.watch() only notifies on data changes that have persisted to a majority of data-bearing members as the document (update, delete, insert).
Try to use Command Monitoringto monitor the success or failure of commands sent to Mongo Database.
Example:
const { MongoClient } = require("mongodb");
const mongo_client = new MongoClient("mongodb://localhost", { monitorCommands:true });
mongo_client.on('commandStarted', (event) => {
if(["find", "aggregate"].includes(event.commandName)){
console.log({
requestId: event.requestId,
database: event.databaseName,
commanName: event.commandName,
collection: (event.commandName=="find")? event.command.find : event.command.aggregate,
query: (event.commandName=="find")? event.command.filter : event.command.pipeline
})
}
})
mongo_client.on('commandStarted', (event) => {
if(["find", "aggregate"].includes(event.commandName)){
console.log({
requestId: event.requestId,
result: event.reply.cursor.firstBatch
})
}
})
Related
I'm making a discord bot to scrape prices from Amazon. Im using a mongoDB database to store links users give to the bot to track the price of the item the link leads to.
My issue is when I run my code and use the add command, my console reads...
Starting...
Online! Logged in as Amazon Price Tracker#6927
Connected to Database
null
MongooseError: document must have an _id before saving
at C:\Users\logic\Documents\Disc Bot\node_modules\mongoose\lib\model.js:291:18
at processTicksAndRejections (node:internal/process/task_queues:78:11)
Disconnected from Database
I've read the doc's and my understanding is mongoose generates a unique id automatically. I am aware that you can override this my defining an id in your schema, but I haven't done this so I don't know why console.log(a) prints null, and the .save() errors out.
My add.js file
//add function using mongoose for mongodb
const { SlashCommandBuilder } = require("#discordjs/builders");
const mongoose = require("mongoose");
const { MongoDBurl } = require("../config.json");
const Link = require("../Schemas/Link.js");
module.exports = {
//Build the slash command
data: new SlashCommandBuilder()
.setName("add")
.setDescription("add a url to watch list")
.addStringOption(option =>
option.setName("url")
.setDescription("url to add to watch list")
.setRequired(true),
),
//Function that runs when the command is used
async execute (interaction) {
const URL = interaction.options.getString("url");
const user = interaction.user.username;
await interaction.reply(`On it! Adding ${URL} to your watch list`)
//Connect to the database, throws an error if it can't connect
await mongoose.connect(MongoDBurl)
.then( () => console.log("Connected to Database"))
.catch(err => console.log(err));
//Check if the link is already in the database
var exists = await Link.exists({ link: URL}).exec()
.catch(err => console.log(err))
if (exists) {
console.log("This Document Already Exists")
interaction.editReply(`Oops! That link is already in my database.`)
} else {
//If the link dosen't exist, create a document and save it to the database
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
// Debuging variable
var a = newLink.id;
console.log(a)
await newLink.save()
.then( () => {
console.log("Document Saved")
interaction.editReply(`All done! I have saved ${URL} to your watch list.`)
})
.catch(err => {
console.log(err)
interaction.editReply("Oops! Something went wrong, I wasen't able to save this link.")
})
}
//Close the connection when we finish
await mongoose.connection.close()
.then( () => console.log("Disconnected from Database"))
}
};
My Link.js file
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const LinkSchema = new Schema({
user: {
type: String,
requiered: true
},
link: {
type: String,
requiered: true
},
price: {
type: String,
requiered: true
},
})
module.exports = mongoose.model("Link", LinkSchema);
When creating a new modal, the options must be within the same pair of curly braces, however when updating, its separate since you are changing multiple elements.
That's why the error was occurring. You have already shared a working piece of code so I'm guessing you no longer need one.
So I found my issue. I changed this line
var newLink = new Link({ user: user }, { link: URL }, { price: "N/A" })
To
const newLink = new Link({ user: user, link: URL, price: "N/A" });
I don't know why this fixed it, I don't think its because I changed var -> const, and looking at the documentation I thought the first line was the correct way to do this
The line I originally used from the documentation
Tank.updateOne({ size: 'large' }, { name: 'T-90' }, function(err, res) {
// Updated at most one doc, `res.nModified` contains the number
// of docs that MongoDB updated
});
Is this an error in the documentation? or a possible bug? either way the issue is now resolved.
I wrote code in node.js for find result from model mongoDB use mongoose
but i want get the result that include status equal waiting or accepted
This is my code that finds me results with waiting status
const Booking= require('../model/Booking')
displayBookings: async(req,res)=>{
console.log('ok get')
try {
Booking.find({owner:req.params.id, status:'waiting'}).populate('driver').exec((err,result)=>{
if(result){
res.json({result:result})
}
else
res.json({error:err})
})
} catch (err) {
res.json(err)
}
},
And this my routing code
const ControllerBooking=require('../conroller/booking')
router.get('/displayBookings/:id', ControllerBooking.displayBookings)
Booking.find({ owner: req.params.id,
status: { $in: ['waiting', 'accepted']} })
MongoDB official Documentation for $in operation
I am trying to update my document field with the following code, but I catch an error "Cannot GET /updation".
My code:
router.put('/updation', (req, res) => {
const query = { email: "babra#arzepak.com" };
const newEmail = { $set: { name: "babra", email: "nadralatif952#gmail.com" } };
Registration.updateOne()
.then((registration) => {
console.log("updating");
res.render('index', { title: 'updating registrations', registrations });
})
.catch(() => {
res.send('Sorry! Something went wrong.');
});
});
send a request with PUT method and you didn't use of query and newEmail as arguments for updateOne() pass them, and in new version of mongoose you don't need to $set for updating so change your code like this :
router.put('/updation', (req, res) => {
const query = { email: "babra#arzepak.com" }
const newEmail = { name: "babra", email: "nadralatif952#gmail.com" }
Registration.updateOne(query,newEmail)
.then((registration) => {
console.log("updating")
res.render('index', { title: 'updating registrations', registrations });
})
.catch(() => { res.send('Sorry! Something went wrong.'); });
})
Wrong Method
In your router you registered a route '/updation' for PUT method.
Hence only request with method PUT will be handled by your router. The error Cannot GET /updation means you are trying to handle a request with GET method which is simply not registered by your router.
A - If this code is supposed to get triggered when you visit the page via browser, then you should register the route for GET method, like router.get('/updation', ... ),
or
B - If this code is supposed to run seperate from your view (like a REST API should), then use a PUT request and end the request inside your router with res.status(200).json(yourdata)
📑 Sidenote :
It looks like you did not completely setup your mongoose query, I mean you defined the query but you don't use it in the database request. To use the defined query you propbably should change your code, according to the mongoose docs : https://mongoosejs.com/docs/api/model.html#model_Model.updateOne . I am not including a specific code example here, since it's not part of the question.
I've been trying to simply update a CosmosDB document via the mongodb api in my node application, I've been testing in and out, no errors but the value does not update no matter what.
I know updating array elements is not supported which is fine, but this is a top-level key-value pair. Changes simply don't happen with no error whatsoever.
I've been following the Mean.js project with uses CosmosDB + Mongoose + Node + Angular, looking at the API for updating hero and trying some of that code but it still doesn't update.
I've been reading the documentation trying to figure out the default way of handling CRUD operations within CosmosDB and which parts of the MongoAPI it supports but so far no luck.
For tests purposes, I'm using this code:
async function updateUser(id) {
try {
let user = await User.findById(id);
console.log (id);
console.log(user);
if (!user) return
user.id = id
user.firstName = 'ASDASDASASDASDASDASDASDA'
const result = await user.save()
console.log(result);
}
catch(err) {
console.log("There was an error updating user", err);
}
}
So, I've been playing around some more and managed to update a hero using this code:
updateHero('10')
async function updateHero(id) {
const originalHero = {
uid: id,
name: 'Hero2',
saying: 'nothing'
};
Hero.findOne({ uid: id }, (error, hero) => {
hero.name = originalHero.name;
hero.saying = originalHero.saying;
hero.save(error => {
return(hero);
console.log('Hero updated successfully!');
});
});
}
Now I'm just not sure why this has actually worked and why it hasn't before. The main thing that is different is that I'm using an 'uid' instead of the actual ID assigned by CosmosDB.
I tested sample code you provided and they both updated document successfully.
Sample document:
Snippet One:
updateUser('5b46eb0ee1a2f12ea0af307f')
async function updateUser(id) {
try {
let user = await Family.findById(id);
console.log (id);
console.log(user);
if (!user) return
user.id = id
user.name = 'ASDASDASASDASDASDASDASDA'
const result = await user.save()
console.log(result);
}
catch(err) {
console.log("There was an error updating user", err);
}
}
Output One:
Snippet Two:
updateFamily('5b46eb0ee1a2f12ea0af307f')
async function updateFamily(id) {
const updateFamily = {
_id: id,
name: 'ABCD',
};
Family.findOne({ _id : id }, (error, family) => {
family.name = updateFamily.name;
family.save(error => {
console.log(JSON.stringify(family));
console.log('Hero updated successfully!');
return(family);
});
});
}
Output Two:
In addition, you could use db.collection.update() to update document.
db.families.update(
{ _id: '5b46eb0ee1a2f12ea0af307f' },{ $set:
{
name: 'AAAA'
}
})
More details,please refer to the doc: https://docs.mongodb.com/manual/reference/method/db.collection.update/
Hope it helps you.
There are some similar questions but all of them involves using the MongoDB NodeJS driver instead of Mongoose ODM.
I read the docs but couldn't find such functionality.
You can't directly get the list from the connection provided by mongoose, but it's easy to do with the mongo Admin object as it contains a function called listDatabases:
var mongoose = require('mongoose')
, Admin = mongoose.mongo.Admin;
/// create a connection to the DB
var connection = mongoose.createConnection(
'mongodb://user:pass#localhost:port/database');
connection.on('open', function() {
// connection established
new Admin(connection.db).listDatabases(function(err, result) {
console.log('listDatabases succeeded');
// database list stored in result.databases
var allDatabases = result.databases;
});
});
A very modern approach to get list of all mongo databases using mongoose (version 6.10.*) is to Create a mongoose connection to connect to Mongo's admin database and make sure you have an admin user.
Mongoose object is a very complex object. To list the db's :
const connection = `mongodb://${encodeURIComponent(username)}:${encodeURIComponent(password)}#${hostname}:${port}/admin`
mongoose is a very complex object with promises for executing several functions. to list the db's :
mongoose.connect(connection, { useNewUrlParser: true , useUnifiedTopology: true }).then( (MongooseNode) => {
/* I use the default nativeConnection object since my connection object uses a single hostname and port. Iterate here if you work with multiple hostnames in the connection object */
const nativeConnetion = MongooseNode.connections[0]
//now call the list databases function
new Admin(nativeConnetion.db).listDatabases(function(err, results){
console.log(results) //store results and use
});
})
Result:
{ databases:
[ { name: 'admin', sizeOnDisk: 184320, empty: false },
{ name: 'config', sizeOnDisk: 73728, empty: false },
{ name: 'local', sizeOnDisk: 73728, empty: false },
{ name: 'test', sizeOnDisk: 405504, empty: false } ],
totalSize: 737280,
ok: 1 }
If someone is looking for answers from the latest version of Mongoose and Mongodb, the below code can be used.
import mongoose from 'mongoose';
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://localhost:27017/mydb', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = mongoose.connection;
// Check DB Connection
db.once('open', () => {
(async () => {
const data = await mongoose.connection.db.admin().command({
listDatabases: 1,
});
console.log(data);
})();
console.log('Connected to MongoDB');
});
// Check for DB errors
db.on('error', (err) => {
console.log('DB Connection errors', err);
});
export default mongoose;
If you want to get the database list on your other functions, make sure the connection is established first and also make sure the user has admin access and then just do the below query. This is a sample from my API router.
// Get all databases
router.get('/database/get', async (req, res) => {
try {
const data = await mongoose.connection.db.admin().command({
listDatabases: 1,
});
if (data && data !== null) {
res.status(200).send({ data: data });
return;
}
res.status(200).send({ data: null, message: 'Data not found' });
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
res.status(500).send(e.message);
}
});
Try running this code. Original take from Gist.