Remove object by id from an array in mongoose - node.js

So this seems pretty straightforward but I cant seem to get it to work.I have a document in mongodb and i m using mongoose All i need to do is find user by id, get the document and delete one specified object from an array of objects. Here is the Structure:
report:[
{
asset_report_id:234,
name:'somethign,
},
{
asset_report_id:23,
name:'somethign,
},
{
asset_report_id:111,
name:'somethign,
}
]
I tried this :
User.findOne({_id: request.decodedTokenData.userId})
.exec()
.then(user=>{
const result = user.reports.find( ({ asset_report_id }) => asset_report_id === assetID );
console.log('IN FIND',result);
})
.catch(err=>console.log(err))
Now i do get the result which is great and i can delete but isn't there a method to do it with mongoose directly? More alongthe lines of plain mongo version of :
db.removeObject.update( {'_id':ObjectId("5c6ea036a0c51185aefbd14f")},
{$pull:{"reports":{"asset_report_id":234}}},false,true);

So the correct solution is:
await User.updateOne( {'_id':ObjectId("5c6ea036a0c51185aefbd14f")},
{$pull:{"report":{"asset_report_id":234}}},false,true)
since the data model contains "report" array

Related

Mongoose Model.find() methods query string not working

im trying to make simple rest api. I have a collection in mongodb and i connected my db to my app with mongoose pkg. I can access all items without query strings with Operator.find() but it doesn't work with query string ex: Operator.find({name:'Kapkan'}) it returns all of them. Also Operator.findOne({name:'Azami'}) doesn't work either. The query string returns the first element of the collection no matter what.
app.get('/api/operators',async(req,res) => {
let operators;
try{
if(req.query.name){
Operator.find({name:'Kapkan'}).then((data) => {
console.log(data);
});
}
else
operators = await Operator.find();
res.send(operators)
}catch(er){
console.log(er);
}
})
You are not assigning result of query with filter to operators. Unsure if you have {} around else or not but try refactoring the code as shown below:
app.get('/api/operators',async(req,res) => {
const filters = {};
if (req.query.name) {
filters.name = req.query.name;
}
const data = await Operator.find(filters);
console.log(data);
return res.json({ data });
})
I checked my Schema and i realize i forgotten put name field...
const OperatorSchema = new Schema({
_id:Number,
logo:String,
image:String,
unit:String,
*name:String,
side:String,
.
.
.
})

Mongoose deleteMany using _id on nodejs

i have a ids of array ['123','456', '789']. i want delete all this array in mongodb
How i user it:
ScheduleModel.deleteOne({ _id: ['123','456', '789'] });
this is not working because this is not object Id
what i Need :
ScheduleModel.deleteOne({ _id: [ObjectId('123'), ObjectId('456'), ObjectId('789')] });
How to add object Id in array data. any how to resolve this issues. i need a solution on this.
It's not about ObjectId. you are using wrong syntax. You must use $in statement
ScheduleModel.deleteMany({ id: { $in: ['123','456','789'] } });
Use deleteMany with proper syntax.When there are many objectId at time Use $in.
Try this :
var deleteCondition = {
_id : {
//In Array you can pass your objectId
$in : ['123','456','789']
}
//You can pass other conditions
}
//deleteMany
ScheduleModel.deleteMany(deleteCondition, function (err, res) {
if (res) console.log(res)
})

Node.js and Mongoose. Reading from one collection and writing to a different one

I am trying to read from one Mongo collection and then take all that data and save it to a new collection. I am using the same schema, but changing the collection name in two different models :
UserInfo.js :
const mongoose = require('mongoose')
const userSchema = mongoose.Schema({
userID : String,
userName : String
})
let userInfo = mongoose.model('UserInfo', userSchema)
let backUpUserInfo = mongoose.model('BackUpUserInfo', userSchema)
module.exports = {
userInfo : userInfo,
backUpUserInfo : backUpUserInfo
}
I inserted data into the userinfos collection and then I am trying to read that and insert into the backupuserinfos collection :
backup.js :
const UserInfo = require('../Schema/UserInfo').userInfo;
const BackUpUserInfo = require('../Schema/UserInfo').backUpUserInfo;
async function backUp(){
UserInfo.find({}, async function(err1, userInfo){
if (err1) return console.log(err1)
for(let i in userInfo){
try{
let backUpUser = new BackUpUserInfo(userInfo[i])
await backUpUser.save(function (err2, user) {
if (err2) return console.error(err2)
console.log("collection updated")
})
}
catch(err){
console.log(err)
}
}
})
}
I am getting an error that seems to indicate that it is finding a duplicate when trying to save the information, even though the backup collection is empty. This makes me think it is trying to write to the user info collection instead of the back up one. I created the backUp model variable and that is what I run save on, which makes me think it should be specified to run to that collection. Am I doing something wrong here?
Here is the error :
VersionError: No matching document found for id
Easiest way in mongoose would be
UserInfo.aggregate([ { $match: {} }, { $out: "BackupUserInfo" } ])
Else you can use mongodb query OR mongodb copyTo()
db.myoriginal.aggregate([ { $match: {} }, { $out: "mycopy" } ])
//OR
db.source.copyTo("target");
But copyTo() is deprecated since version 3.0.

Mongoose find and findById inconsistency

I'm testing mongoose queries, and I found this bizarre behaviour. I have a document with _id: "5de64b376c79643fa847e86b", and if I call the findById method the document is returned just fine. But if I call the find method on the collection, giving as args an array with the same ID value than nothing is returned, while I expect an array of one element being the document. To summarize:
mongooseModel.findById(mongoose.Types.ObjectId("5de64b376c79643fa847e86b")) // Works
mongooseModel.find({ _id: { $in: [mongoose.Types.ObjectId("5de64b376c79643fa847e86b")] } }) //Doesn't work
What's the difference between the two, and why the second one doesn't work?
EDIT: This is kinda the code to access that method.
I define a DataSource in the ApolloServer configuration
const app = new ApolloServer({
...
dataSources: () => ({
source: new SourceAPI(DocumentModel)
})
...
});
where SourceAPI is the DataSource class and DocumentModel is the mongoose model.
SourceAPI is defined like this
class SourceAPI {
async get(ids) {
return await DocumentModel.find({
_id: {
$in: ids
}
});
}
}
Now, inside the GraphQL resolver I finally call the API method to get the documents, like this
const findResolver = () =>
DocumentSchema.get("$findById").wrapResolve(next => async rp => {
let ids = [];
ids.push(mongoose.Types.ObjectId(rp.args._id));
return await rp.context.dataSources.source.get(ids);
});
where DocumentSchema is the GraphQL Schema for the Document Model generated using graphql-compose-mongoose package. The get("$findById") and wrapResolve methods are also from that package. What I do is using these methods to get the GraphQL query parameters and pass them to the API method (in this case I'm just grabbing an ID for test).
If I change the API method to something like this
async get(id) {
return await DocumentModel.findById(id);
}
and the resolver method to this
const findResolver = () =>
DocumentSchema.get("$findById").wrapResolve(next => async rp => {
return await rp.context.dataSources.source.get(mongoose.Types.ObjectId(rp.args._id));
});
everything works
$in is used to find items which holds an array, but _id is just a JSON key/value pair. So you cannot use $in. If your object looks like this then you can use $in
{
id: [ObjectId("5de64b376c79643fa847e86b"),
ObjectId("5de64b376c79643fa847e86b")]
}

Data is mutated but not updated in the database

I have a sever connected to a mongodb database. When I add a first level data and then save that, it works.
For example :
// this works fine
router.post('/user/addsomedata', async (req,res)=>{
try {
const user = await User.findOne({email : req.body.email})
user.username = req.body.username
await user.save()
res.send()
} catch(e) {
res.status(404).send(e)
}
})
BUT if I try to save the object with deeper level data, it's not getting saved. I guess the update is not detected and hence the user didn't get replaced.
Example :
router.post('/user/addtask', auth ,async (req,res)=>{
const task = new Task({
name : req.body.name,
timing : new Date(),
state : false,
})
try {
const day = await req.user.days.find((day)=> day.day == req.body.day)
// day is found with no problem
req.user.days[req.user.days.indexOf(day)].tasks.push(task)
// console.log(req.user) returns exactly the expected results
await req.user.save(function(error,res){
console.log(res)
// console.log(res) returns exactly the expected results with the data filled
// and the tasks array is populated
// but on the database there is nothing
})
res.status(201).send(req.user)
} catch(e) {
res.status(400).send(e)
}
})
So I get the tasks array populated on the console even after the save callback but nothing on the db image showing empty tasks array
You're working on the user from the request, while you should first find the user from the DB like in your first example (User.findOne) and then update and save that model.
Use .lean() with your find queries whenever you are about to update the results returned by mongoose. Mongoose by default return instance objects which are immutable by nature. lean() method with find returns normal js objects which can be modified/updated.
eg. of using lean()
const user = await User.findOne({email : req.body.email}).lean();
You can read more about lean here
Hope this helps :)

Resources