The following is using nodejs, expressjs, mongodb. On the live site it is using mongolab. I am making a POST request from the front end to the server, and the server handles the request by deleting a single matching record from the database. The server work (done in ExpressJS is as follows:
var removeStuff = req.body.removeStuff;
var currentId = req.user._id;
var currentEmail = req.user.email;
myStuff.findOne({
$and: [
{ $or: [{stuff: removeStuff}] },
{ $or: [{apid:currentId},{apiemail:currentEmail}] }
]
}, function (err, currentStuff) {
currentStuff.remove();
res.send('Stuff was removed from database...')
});
What's really strange is that this works perfectly for the site when I'm running it on localhost. But when it's live, making the request removes ALL records from the database.
Ok, I got it. I'm not sure exactly why the original doesn't work, but I found that in this StackOverflow question someone answered a similar question. What they did was along the lines of:
var removeStuff = req.body.removeStuff;
var currentId = req.user._id;
var currentEmail = req.user.email;
myStuff.findOneAndRemove({
$and: [
{ $or: [{stuff: removeStuff}] },
{ $or: [{apid:currentId},{apiemail:currentEmail}] }
]
}, function (err) {
res.status(200).send("it worked...");
});
Related
I'm running a Node.js server, connecting to a MongoDB database with mongoose.
Inside my controller, I have several methods that make operations to the database. One of them is this one:
async findMultiple(req, res) {
const [baseSkillsArray] = Array(req.body);
try {
// if there is not baseSkillsArray, skip
if (!baseSkillsArray) {
return res.status(200).send([]);
}
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({
_id: { $in: [baseSkillsArray.baseSkillArray] } //
});
console.log('test ' + allBaseSkills);
res.status(200).send(allBaseSkills);
} catch (error) {
console.error(error.message);
res.status(500).send('Server error find BaseSkills');
}
}
However, this returns me nothing. I did some debugging and I found the reason is the find id $in the array. So I tried hard coding a value, like '2', for instance.
// find all baseSkills using the ids in the baseSkillsArray
const allBaseSkills = await BaseSkill.find({ _id: { $in: ['2'] } });
No success. So I went to MongoDB Atlas, where my DB is stored. I tried filtering using the same line of code in my collections.
{ _id: { $in: ['2'] } }
Surprisingly, it returns my document as I wanted!
The issue is that I need to make it work with mongoose. Any ideas? Is this a known bug?
There is nothing wrong with the query, nor a bug regarding $in.
In fact, what's wrong is the actual collection name. I manually created a collection in MongoDB Atlas, called "baseSkills". However, mongoose by default transforms your collection name into lowercase and adds an "s" if your collection's name is not in the plural.
So every time I started my server, I noticed that there was a new collection called "baseskills". I assumed it was a bug and deleted it. Only after making this post that I realized the collection was there again.
So I exported the documents to this collection and my query was working fine.
FYI, there is a way to enforce the collection's name in mongoose. When you declare you model, add a second parameter to the Schema function called "collection". Here is an example:
const BaseSkillSchema = new mongoose.Schema({
_id: {
type: String,
required: true
}, ...
}, { collection: 'baseSkills' })
That's it! Sorry for the mess and thank you for your help!
you want to query over mongo db object ids. So you should create a new ObjectId to do that.
import {Types} from 'mongoose';
{ _id: { $in: [new Types.Object("2")] } }
Or if you have 2 ids one generated and one custom created as id then you can query without creating a new object.
{ id: { $in: ['2'] } }
I have some code that watches a mongodb collection for updates... I have it setup so that when anyone sends a message, the changestream will detect that... The issue is that when I try to add a pipeline, the updates do not get detected...
Here are some things that I've tried:
const pipeline = [
{ $match: { 'fullDocument.username_pair': 'HardCodedUsernameInDatabase' }}
];
changeStream = message_collection.watch(pipeline);
and
const pipeline = [
{ $match: { username_pair: 'HardCodedUsernameInDatabase' }}
];
changeStream = message_collection.watch(pipeline);
again, the code will detect all messages in the absence of any pipeline, ie:
changeStream = message_collection.watch();
...
UPDATE:
The reason why this is tricky is because the document I'm listening to looks like this:
_id:some_id
username_pair:"Test1234test1111"
messages:Array
The username_pair never updates, the messages array is what updates... I need to be looking at the document matching the username_pair, and I need to detect changes in the messages array that corresponds to the username_pair.
I guess the trick is to add option called fullDocument while opening the change stream on collection. see here
someCollection.watch([{
"$match": {
"operationType": {
"$in": ["update"]
},
"fullDocument.username_pair": "HardCodedUsernameInDatabase"
}
}], {"fullDocument": "updateLookup"})
Hope this helps
I've been trying to setup a rest API for a few days now. I've been following a great tutorial that really helped me understand a large part of how these work (sending requests, getting responses, etc). However it uses MongoDB and Mongoose. I'm using MySQL. My tables and views are a bit complicated so I decided instead of using an ORM I'd just use mysql2 package and do the querying myself. I'm stuck with trying to PATCH and PUT at the moment. Part of my front end functions by sometimes only sending 1 or 2 fields that need to be updatd (a PATCH from everything I've gathered). So I used part of the MongoDB and Mongoose tutorial to build an array of objects and pass them into connection.query. Here's my patch route:
router.patch('/:txnid', (req, res, next) => { //UPDATE fields that are passed
const txnid = req.params.txnid;
for (const field of req.body) {
fieldsToUpdate[field.name] = field.value;
}
connection.query("UPDATE QuoteToClose SET ? WHERE qb_TxnID = '" + txnid + "'", { fieldsToUpdate }, function (error, results) {
if (error) {
res.status(404).json({
message: error,
field: fieldsToUpdate
});
} else {
res.status(201).json({
"record_count" : results.length,
"error": null,
"response": results
});
}
});
});
Sometimes I will pass 1 field, sometimes I will pass 2. In this case I'm only passing 1. I build my body in POSTMAN and send this with the PATCH request:
[
{
"name": "margin",
"value": "50"
}
]
When I run this through POSTMAN I get the error:
{
"message": {
"code": "ER_BAD_FIELD_ERROR",
"errno": 1054,
"sqlState": "42S22",
"sqlMessage": "Unknown column 'fieldsToUpdate' in 'field list'"
},
"field": {
"margin": "50"
}
}
I'm not sure why though. I'm not using Mongoose unfortunately so I don't know if something is dependent on it that I'm missing. My body parser is set like this:
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
I want to dynamically build that query instead of specifying each field (it just seems cleaner this way.
Hi im using this library build dynamic queries.https://www.npmjs.com/package/flexqp
let result = await qp.executeUpdatePromise('update user set ? where user.id = ?', [user, user.id], dbconfig);
user is an object with lots of sub elements, the library will auto populate the
query to E.g update user set name = 'xxx' , address ='xxx' ..etc where user.id = 1
fieldsToUpdate is already an object. If you remove the curlies when you parameterize if you should be good to go:
connection.query("UPDATE QuoteToClose SET ? WHERE qb_TxnID = '" + txnid + "'", fieldsToUpdate,
Also, as a side note that string concatenation is a bad idea, you're just asking for a SQL Injection attack.
on serverside, i get a simple json file via REST with a lot of IDs, something like that:
[ {
"_id": "5825a49dasdasdasd8417c1b6d5",
}
"_id": "dfsdfsdf4960932218417c1b6d5",
}
"_id": "23434344960932218417c1b6d5",
},]
For that i have written in the main:
main.post('/..../add', Controller.addEvent);
In the Controller, i want to recieve the request and search in the mongodb for these ID's, because i need some informations about these IDs
exports.addEvent = function(req, res) {
var collection = db.get().collection('events');
My question is, if someone send me over "localhost:8080/events/add" the given simple json file, how do i have to handle this json? i need the ID's and want to search with them.
Thanks for help!
----------ADDED------------
I am bit further now. In my controller i have the following function
exports.addevent = function(req, res)
{
var ids = req.body;
console.log(ids);
}
Now i'm getting all IDs, which i have posted with "Postman" from chrome.
The output in the console is:
[ { _id: '5825a49dasdasdasd8417c1b6d5' },
{ _id: 'dfsdfsdf4960932218417c1b6d5' },
{ _id: '23434344960932218417c1b6d5' } ]
How can i have every single ID?
Ok, the request is an object and not a string. That was the error :-/
for(var i in ids) {
console.log(ids[i]._id);
}
and it works, now i can connect to the database and search for the id
Sorry if I'm not getting the terminology right. Here's what I have currently my MongoDB user docs db.users:
"liked" : [
"EBMKgrD4DjZxkxvfY",
"WJzAEF5EKB5aaHWC7",
"beNdpXhYLnKygD3yd",
"RHP3hngma9bhXJQ2g",
"vN7uZ2d6FSfzYJLmm",
"NaqAsFmMmnhqNbqbG",
"EqWEY3qkeJYQscuZJ",
"6wsrFW5pFdnQfoWMs",
"W4NmGXyha8kpnJ2bD",
"8x5NWZiwGq5NWDRZX",
"Qu8CSXveQxdYbyoTa",
"yLLccTvcnZ3D3phAs",
"Kk36iXMHwxXNmgufj",
"dRzdeFAK28aKg3gEX",
"27etCj4zbrKhFWzGS",
"Hk2YpqgwRM4QCgsLv",
"BJwYWumwkc8XhMMYn",
"5CeN95hYZNK5uzR9o"
],
And I am trying to migrate them to a new key that also captures the time that a user liked the post
"liked_time" : [
{
"postId" : "5CeN95hYZNK5uzR9o",
"likedAt" : ISODate("2015-09-23T08:05:51.957Z")
}
],
I am wondering if it might be possible to simply do this within the MongoDB Shell with a command that iterates over each user doc and then iterates over the liked array and then updates and $push the new postId and time.
Or would it be better to do this in JavaScript. I am using Meteor.
I almost got it working for individual users. But want to know if I could do all users at once.
var user = Meteor.users.findOne({username:"atestuser"});
var userLiked = user.liked;
userLiked.forEach(function(entry) {
Meteor.users.update({ username: "atestuser" },
{ $push: { liked_times: { postId: entry, likedAt: new Date() }}});
console.log(entry);
});
Still a bit of a newbie to MongoDB obviously......
Here is something i made real quick you should run this on the server side just put it into a file e.g. "migrate.js" in root meteor and run the meteor app
if (Meteor.isServer) {
Meteor.startup(function () {
var users = Meteor.users.find().fetch();
users.forEach(function (doc) {
liked.forEach(function (postId) {
Meteor.users.update(doc._id, { $push: { liked_times: { postId: postId, likedAt: new Date() } } });
});
});
console.log('finished migrating');
});
}
p.s I didn't test it
If this is a one time migration i would do something like this in a one time js script.
Get all users
Iterate over each user
Get all likes
Iterate over them, get likedAt
var liked_times = _.collect(likes, function (likeId) {
return {
'postId' : likeId,
'likedAt': // get post liked time from like id.
}
});
Insert the above in the collection of choice.
Note:
The above example makes use of lodash
I would rather just save likedAt as a timestamp.