New to MongoDB. I'm trying to add a new document to an existing collection only if a document with the same name does not already exist within that collection. I'm using an if/else statement first to check whether there is a document with the same name as the new entry, and if not, an else statement that will create the new entry. Whatever I try, the new document is not getting added, and instead it returns an empty array. I'd be grateful for any help.
I've tried switching the if/else statements; checking for null and undefined values upon return of if statement
app.post('/cocktails/new', isLoggedIn, (req, res) => {
// add to DB then show item
let name = req.body.name;
let style = req.body.style;
let spirit = req.body.spirit;
let image = req.body.image;
let description = req.body.description;
let newCocktail = {name: name, style: style, base: spirit, image:
image, description: description}
Cocktail.find({name}, function (err, existCocktail) {
if(existCocktail){
console.log(existCocktail)
}
else {Cocktail.create(newCocktail, (err, cocktail) => {
console.log(cocktail)
if (err) {console.log(err)}
else {
res.redirect('/cocktails/' + cocktail._id)}
})
}
})
})
In the event document is not found with the if function, else statements will execute, leading to new document being created with the newCocktail object.
You should use findOne instead of find.
find returns an empty array when no docs found.
The following expression returns true, so your existCocktail condition becomes true, causing your new data not added.
[] ? true : false
Also I refactor your code a bit, you can use destructuring your req.body.
app.post("/cocktails/new", isLoggedIn, (req, res) => {
// add to DB then show item
const { name, style, spirit, image, description } = red.body;
let newCocktail = {
name,
style,
base: spirit,
image,
description
};
Cocktail.findOne({ name }, function(err, existCocktail) {
if (existCocktail) {
console.log(existCocktail);
res.status(400).json({ error: "Name already exists" });
} else {
Cocktail.create(newCocktail, (err, cocktail) => {
console.log(cocktail);
if (err) {
console.log(err);
res.status(500).json({ error: "Something went bad" });
} else {
res.redirect("/cocktails/" + cocktail._id);
}
});
}
});
});
Related
I am trying to return all the records that match my searchtext.So far I have only seen examples where we need to specify field name but I want return records if any of the field contains the searchtext, without specifying any field name. And I got to see $text , but unfortunatly it's not supported in cosmosdb API mongodb.
Can someone please help me to resolve this issue ?
Here is what I tried but failed
let querySpec = {
entity: "project",
$text: { $search: "\"test\"" } ,
$or: [{
accessType: "Private",
userName: userName
}, {
accessType: "Public"
}]
}
dbHandler.findandOrder(querySpec, sortfilter, "project").then(function (response) {
res.status(200).json({
status: 'success',
data: utils.unescapeList(response),
totalRecords:response.length
});
exports.findandOrder = function (filterObject, sortfilter, collectionname) {
return new Promise((resolve, reject) => {
return getConnection().then((db) => {
if (db == null) {
console.log("db in findandOrder() is undefined");
} else {
db.db(config.mongodb.dbname).collection(collectionname).find(filterObject).sort(sortfilter).toArray((err, res) => {
if (db) {
//db.close();
}
if (err) {
reject(err);
} else {
resolve(res);
}
});
}
});
});
};
Error:
{"message":{"ok":0,"code":115,"codeName":"CommandNotSupported","name":"MongoError"}}
I am using $regex as temperory solution as $text is not supported.
Please suggest ...
From the MongoDB manual, Create a Wildcard Index on All Fields:
db.collection.createIndex( { "$**" : 1 } )
but this is far from an ideal way to index your data. On the same page is this admonition:
Wildcard indexes are not designed to replace workload-based index planning.
In other words, know your data/schema and tailor indices accordingly. There are many caveats to wildcard indices so read the manual page linked above.
Alternately you can concatenate all the text you want to search into a single field (while also maintaining the individual fields) and create a text index on that field.
I want to add a new document to an array of documents. So I pass in my param which is the _id of the document I want to add to. Then I need to just add it to the array. I thought I had it working but it was actually adding a nested array to that array. I realized this because I am also trying to sort it so newly added documents are at top. So I ended up having to go back and try and fix my add query. As of now it basically just says cannot add values. This is why I have been using mongodb client, express, await.
I have been looking at mongodb manual and trying what they have but cannot get it to work, obviously something wrong with my adding of new document. Anyone see the issue or show me an example? Thanks!
app.post("/addComment/:id", async (request, response) => {
let mongoClient = new MongoClient(URL, { useUnifiedTopology: true });
try {
await mongoClient.connect();
let id = new ObjectId(request.sanitize(request.params.id));
request.body.comments = { $push: {"comments.author": "myTestPOSTMAN - 1", "comments.comment":
"myTestCommPostMan - 1"}};
let selector = { "_id":id };
//let newValues = {$push: {"comments.comment": "myTestCommPostMan - 1", "comments.author":
"myTestPOSTMAN - 1"}};
let newValues = request.body.comments;
let result = await mongoClient.db(DB_NAME).collection("photos").updateOne(selector,
newValues);
if (JSON.parse(result).n <= 0) {
response.status(404);
response.send({error: "No documents found with ID"});
mongoClient.close();
return;
}
response.status(200);
response.send(result);
} catch (error) {
response.status(500);
response.send({error: error.message});
throw error;
} finally {
mongoClient.close();
}
});
Using post man this is what my json looks like and what the array of documents looks like I am trying to add to.
{"comments": [
{
"comment": "pm - test3",
"author": "pm - test4"
}
]
}
do the mongodb connection outside the function, no need to connect and disconnect everytime when function call, don't create unusual variables too much.
for push object you need to provide main key name and assign object to it.
let mongoClient = new MongoClient(URL, { useUnifiedTopology: true });
await mongoClient.connect();
app.post("/addComment/:id", async (request, response) => {
try {
let result = await mongoClient.db(DB_NAME).collection("photos").updateOne(
{ "_id": new ObjectId(request.sanitize(request.params.id)) },
{ $push: { comments: request.body.comments } }
);
if (JSON.parse(result).n <= 0) {
response.status(404).send({ error: "No documents found with ID" });
return;
}
response.status(200).send(result);
} catch (error) {
response.status(500).send({ error: error.message });
}
});
I designed an API to fetch users from my mongodb in MEAN stack using express and I need to determine if mongodb is returning an empty array. Below is my code:
router.get('/user/:name', function (req, res) {
users
.find({ name: { $regex: '.*' + req.params.name + '.*' } })
.exec(function (err, user) {
if (err) {
console.log(err)
} else if (user === null) {
console.log('user not found')
} else {
res.json(user)
console.log('user found')
}
})
})
I tried querying such that the results would be empty but the console still logs "user found." Please help!
You are using find. This function always returns an array, if no user is found it returns an empty array, which is never equal to null.
If you use the function findOne then a document or null will be returned.
Check the length of the result instead:
} else if (user.length === 0) {
If you want to retrieve only one document, you can use findOne:
users.findOne({name: {$regex: ".*"+req.params.name+".*"}}).exec( // ...
In that case your checks do not need to be changed.
Say I have a list of models:
const documents = [{}, {}, {}];
And I want to insert these into the DB, or update them all, but only if a condition is met:
Model.update({isSubscribed: {$ne: false}}, documents, {upsert:true},(err, result) => {
});
The above signature is surely wrong - what I want to do is insert/update the documents, where the condition is met.
There is this Bulk API:
https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/
but I can't tell if it will work when inserting multiple documents.
Imagine this scenario: We have a list of employees and a form of some sorts to give them all a penalty, at once, not one by one :)
On the backend side, you would have your eg addBulk function. Something like this:
Penalty controller
module.exports = {
addBulk: (req, res) => {
const body = req.body;
for (const item of body) {
Penalty.create(item).exec((err, response) => {
if (err) {
res.serverError(err);
return;
}
});
res.ok('Penalties added successfully');
}
}
Then you'll probably have an API on your frontend that directs to that route and specific function (endpoint):
penaltyApi
import axios from 'axios';
import {baseApiUrl} from '../config';
const penaltyApi = baseApiUrl + 'penalty'
class PenaltyApi {
static addBulk(penalties) {
return axios({
method: 'post',
url: penaltyApi + '/addBulk',
data: penalties
})
}
}
export default PenaltyApi;
...and now let's make a form and some helper functions. I'll be using React for demonstration, but it's all JS by the end of the day, right :)
// Lets first add penalties to our local state:
addPenalty = (event) => {
event.preventDefault();
let penalty = {
amount: this.state.penaltyForm.amount,
unit: this.state.penaltyForm.unit,
date: new Date(),
description: this.state.penaltyForm.description,
employee: this.state.penaltyForm.employee.value
};
this.setState(prevState => ({
penalties: [...prevState.penalties, penalty]
}));
}
Here we are mapping over our formData and returning the value and passing it to our saveBulkEmployees() function
save = () => {
let penaltiesData = Object.assign([], this.state.penalties);
penaltiesData.map(penal => {
penal.employeeId = penal.employee.id;
delete penal.employee;
return penaltiesData;
});
this.saveBulkEmployees(penaltiesData);
}
...and finally, let's save all of them at once to our database using the Bulk API
saveBulkEmployees = (data) => {
PenaltyApi.addBulk(data).then(response => {
this.success();
console.log(response.config.data)
this.resetFormAndPenaltiesList()
}).catch(error => {
console.log('error while adding multiple penalties', error);
throw(error);
})
}
So, the short answer is YES, you can absolutely do that. The longer answer is above :) I hope this was helpful to you. If any questions, please let me know, I'll try to answer them as soon as I can.
When I findOne based on deliverables.steps._id it's returning my entire document rather than just my step with the particular id. Can I not have it return my individual step rather than the whole document? The reason I ask is so when I need to update I just update this step rather than updating the whole document each time.
exports.findStep = function(req, res) {
Project.findOne({'deliverables.steps._id': req.params.stepId}).sort('-created').exec(function(err, step) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(step);
}
});
};