How to remove data in object from MongoDB document - javascript

The object contains the username and category. Categories is another object that contains categories and costs. How can I remove all key-values ​​in a category object? Now in my code, using deleteOne() I find all the fields of the object named "Bob". I am deleting the entire document named "Bob". And I need to clear the categories in this document, for example, deleteOne({ name: "Bob", category }, and have { name: "Bob", category: {} } output to the console
let users = [
{
name: "Bob",
сategories: {
eat: "20$",
entertainment: "100$",
},
},
];
mongoClient.connect(function (err, client) {
if (err) return console.log(err);
const db = client.db("expensesdb");
db.collection("users").deleteOne({ name: "Bob" }, function (err, result) {
console.log(result);
client.close();
});
});

You can use updateOne method to set сategories as empty object using $set or you can use $unset to unset your сategories data.

Related

How to add new value with same key to document

I need to write down a category and its cost in category object. Now, in my code example, I am adding the products: $50 category to the user. After execution, 'categories': { products: '50$' } is displayed in the console. But if you add products: 1000$ again, it will overwrite and output 'categories': { products: '1000$' }. And I need to display 'categories': { products: '$50' , products: '$1000' }. How can this be implemented?
mongoClient.connect(function (err, client) {
if (err) return console.log(err);
const db = client.db("db");
const col = db.collection("coll");
col.findOneAndUpdate(
{
name: "User1",
},
{
$set: {
"сategories.products": "50$",
},
},
function (err, result) {
console.log(result);
client.close();
}
);
});
Instead of
$set: {
"сategories.products": "50$"
}
use
$addToSet: {
сategories: {
products: "1000$"
}
}
Well if I understood you correctly you have an object like categories:{products:$50} but you want that whenever you post a new price it should get added to the object not overwrite it.
I think that is not possible either every time you create a new object like {products1:$50, products2:$1000} and set your categories field to be equal to this new object
OR
you should make your model like categories:{products:[]}. So, that you can just push the new price in the array.

How can I add to this schema array with mongoose?

Here's the user schema and the part I want to update is ToDo under User.js (further down). I am attempting to add new data to an array within the db.
data.js
app.post("/data", loggedIn, async (req, res) => {
console.log(req.body.content);
let content = { content: req.body.content };
User.update({ _id: req.user._id }, { $set: req.body }, function (err, user) {
if (err) console.log(err);
if (!content) {
req.flash("error", "One or more fields are empty");
return res.redirect("/");
}
user.ToDo.push(content);
res.redirect("/main");
});
});
User.js
new mongoose.Schema({
email: String,
passwordHash: String,
ToDo: {
type: [],
},
date: {
type: Date,
default: Date.now,
},
})
Originally I was trying the .push() attribute, but I get the error:
user.ToDo.push(content);
^
TypeError: Cannot read property 'push' of undefined
First of all, your problem is the callback is not the user. When you use update the callback is something like this:
{ n: 1, nModified: 1, ok: 1 }
This is why the error is thrown.
Also I recommend specify the array value, something like this:
ToDo: {
type: [String],
}
The second recommendation is to do all you can into mongo query. If you can use a query to push the object, do this instead of store the object into memory, push using JS function and save again the object into DB.
Of course you can do that, but I think is worse.
Now, knowing this, if you only want to add a value into an array, try this query:
var update = await model.updateOne({
"email": "email"
},
{
"$push": {
"ToDo": "new value"
}
})
Check the example here
You are using $set to your object, so you are creating a new object with new values.
Check here how $set works.
If fields no exists, will be added, otherwise are updated. If you only want to add an element into an array from a specified field, you should $push into the field.
Following your code, maybe you wanted to do something similar to this:
model.findOne({ "email": "email" }, async function (err, user) {
//Here, user is the object user
user.ToDo.push("value")
user.save()
})
As I said before, that works, but is better do in a query.

Node.js - Mongoose - Update nested array with all values in req.body

I have an object that looks like this.
{
_id: '577fe7a842c9b447',
name: 'Jacob\'s Bronze Badges',
competitors: [
{
_id: '577fe7a842c9bd6d',
name: 'Peter\'s Silver Badges',
sites: [
{
_id: '577fe7a842c9bd6d',
name: 'Facebook',
url: 'fb.com/peter'
},
{
_id: '577fe7a842c9bd6d'
name: 'Google',
url: 'google.com/peter'
}
]
},
{
_id: '599fe7a842c9bd6d',
name: 'Paul\'s Gold Badges',
sites: [
{
'_id': '577fe7a842c9bd6d',
name: 'Facebook',
url: 'fb.com/paul'
},
{
_id: '577fe7a842c9bd6d',
name: 'Google',
url: 'google.com/paul'
}
]
}
]
}
My goal is to reference the competitors array and update items inside with all of the values from req.body. I based this code off of this answer, as well as this other one.
Location.update(
{ 'competitors._id': req.params.competitorId, },
{ $set: { 'competitors.$': req.body, }, },
(err, result) => {
if (err) {
res.status(500)
.json({ error: 'Unable to update competitor.', });
} else {
res.status(200)
.json(result);
}
}
);
I send my HTTP PUT to localhost:3000/competitors/577fe7a842c9bd6d to update Peter's Silver Badges. The request body is:
{
"name": "McDonald's"
}
The problem is that when I use $set to set the competitor with _id: req.params.competitorId, I don't know what is in req.body. I want to use the entire req.body to update the object in the array, but when I do, that object is overwritten, so instead of getting a new name, Peter's Silver Badges becomes:
{
name: 'McDonald\'s',
sites: []
}
How can I update an object within an array when I know the object's _id with all of the fields from req.body without removing fields that I want to keep?
I believe that the sites array is empty because the object was reinitialized. In my schema I have sites: [sitesSchema] to initialize it. So I am assuming that the whole competitors[_id] object is getting overwritten with the new name and then the sites: [sitesSchema] from myschema.
You would need to use the $ positional operator in your $set. In order to assign those properties dynamically, based on what is in your req.body, you would need to build up your $set programmatically.
If you want to update the name you would do the following:
Location.update(
{ 'competitors._id': req.params.competitorId },
{ $set: { 'competitors.$.name': req.body.name }},
(err, result) => {
if (err) {
res.status(500)
.json({ error: 'Unable to update competitor.', });
} else {
res.status(200)
.json(result);
}
}
);
One way you might programatically build up the $set using req.body is by doing the following:
let updateObj = {$set: {}};
for(var param in req.body) {
updateObj.$set['competitors.$.'+param] = req.body[param];
}
See this answer for more details.
To update embedded document with $ operator, in most of the cases, you have to use dot notation on the $ operator.
Location.update(
{ _id: '577fe7a842c9b447', 'competitors._id': req.params.competitorId, },
{ $set: { 'competitors.$.name': req.body.name, }, },
(err, result) => {
if (err) {
res.status(500)
.json({ error: 'Unable to update competitor.', });
} else {
res.status(200)
.json(result);
}
}
);

Chaining collection methods / promises in get request Node.js

I'm trying to get some data from a MongoDB database with the find() method, returning only those documents that contain a specified "room". Then, I want to return all distinct values, of the found array of rooms, whose key is equal to "variety". I tried this in two different ways and I could be way off in my approach. The first way was to chain the collection methods find() and distinct(). This did not work:
This is what the plantList collection looks like:
[
{
"_id": {
"$oid": "56c11a761b0e60030043cbae"
},
"date added": "10/21/2016",
"variety": "Lettuce",
"room": "Room 1"
},
{
"_id": {
"$oid": "56c11a761b0e60030043cbaf"
},
"date added": "10/21/2015",
"variety": "Tomatoes",
"room": "Room 2"
}
]
server.js
//plantList = db collection
var mongojs = require('mongojs');
var MongoClient = require("mongodb").MongoClient;
MongoClient.connect(process.env.MONGOLAB_URI, function(err, db) {
var plantList = db.collection("plantList");
app.get('/gettypesbyroom/:room', function(req, res) {
var roomReq = req.params.room;
plantList
.find({"room":roomReq})
.toArray()
.distinct("variety", function(err, docs) {
if (err) throw err;
res.json(docs);
});
});
});
My second approach was to chain promises with .then() and use underscore.js to select the keys of the array of rooms (also did not work):
app.get('/gettypesbyroom/:room', function(req, res) {
var roomReq = req.params.room;
plantList
.find({"room":roomReq})
.toArray(function(err, docs) {
if (err) throw err;
return docs;
}).then(function(docs) {
_.keys(docs, function(docs) { return docs.variety; });
}).then(function(varieties) {
res.json(varieties); //not inside scope of .get function?
});
});
Is there something I could do differently to make these work or perhaps a different approach altogether?
Try calling it without toArray:
//plantList = db collection
app.get('/gettypesbyroom/:room', function(req, res) {
var roomReq = req.params.room;
plantList
.find({ room: roomReq })
.distinct('type', function(err, docs) {
if (err) throw err;
res.json(docs);
});
});
See How Do I Query For Distinct Values in Mongoose.
You can do it two more ways. One is to make it easier with a projection operator - just project what you need. Eg. if you have a document that looks like:
{
room: 123,
type: 'soundproof_room',
other: 'stuff'
}
...you can project it with a query like this to just select the type:
db.rooms.find({ room: room }, { type: 1 }).toArray();
That would give you an array of objects like this:
let roomTypes = [{type: 'soundproof_room'}, {type: 'windy_room'}, {type: 'soundproof_room'}, {type: 'room without doors'}]
(Obviously, I'm making types up, I don't know what they really are.)
And then use a simple map:
return res.json(
roomTypes
// extract the type
.map(room => room.type)
// filter out duplicates
.filter((type, idx, self) => self.indexOf(type) === idx)
);
(I'm using ES6 arrow fn, hope you can read it, if not: babeljs.io/repl/)
Another thing to try is an aggregation.
db.rooms.aggregate({
// first find your room
$match: { room: room }
},
{
// group by type, basically make distinct types
$group: {
_id: '$type',
count: {$sum: 1} // inc this by 1 for each room of this type
}
});
That one would get you your room, and it would return you only the types of rooms and the count per type, as an added bonus.

Looping through array and executing MongoDB query (NodeJS)

I have an object name profile that contains a favorites array that looks like this...
{favorites: [
{ name: 'Love Song',
id: 'Itja90E2tIE'},
{ name: 'I Need Your Love',
id: 'AtKZKl7Bgu0'}
]}
I want to loop through that array, get the id of each favorite, and do a .find() for that ID in my songs collection of my mongo DB, get the song's artist, and add it to the array.
I've tried something like...
for(var i=0; i<profile.favorites.length; i++) {
db.songs.find({"_id" : profile.favorites[i].id}, {"artistName" : 1}, function (e, result){
profile.favorites[i]["artistName"] = result[0].artistName;
});
}
But that doesn't seem to working, (primarily because Mongo/MongoJs is async.)
What is the proper way to do something like this?
You can use $in to query an field that match with any value in the specified array.
favoritesId = favorites.map(function(favorite){ return favorite.id; });
db.songs.find({ _id: { $in: favoritesId }}, function(err, songs){
// do you favor
});

Categories

Resources