Different behavior between mongo and mongoose? - node.js

In the mongo shell I can do this:
db.getCollection('usercourses').update({
_id:ObjectId("54bee7c6ababf28b4ea5a07f")},
{
$unset:{
'steps.0.topic':''
}
},
{strict:false})
And it'll delete the "topic" field from the object inside the array, from the document found.
But when I do this in mongoose:
function() {
return UserCourses.findQ()
.then(function(uCourse){
return Q.all(uCourse.map(worker))
}).catch(function(error) {
console.log(error);
});
}
function worker(uCourse) {
return Q.all(uCourse.steps.map(
function(step,i){
var field1 = 'steps.'+i+'.topic';
return UserCourses.updateQ({_id:uCourse._id},
{
$unset:{field1:''},
},
{strict:false});
}
))
}
Nothing happens.
Why?

Because you're trying to unset a field called field1 (because ES5 doesn't have computed property names):
$unset : { field1 : '' }
Instead, you need to do this:
var obj = {};
obj['steps.'+i+'.topic'] = '';
...
$unset : obj

Related

update data in sub document without overwrite another field in mongoose

data in database
fieldA : 'aaaaa',
fieldB : {
en : 'aaaaaaaaaa',
de : 'bbbbbbbbbb'
}
new data
val = {
fieldA : 'aaaaa11',
fieldB : {
en : 'aaaaa1111'
}
}
i tried this code
Model.findOneAndUpdate({fieldA : val.fieldA},{ $set : val})
when i run this command 'fieldB.de' is missing. i want to know how to update as result seem below
fieldA : 'aaaaa11',
fieldB : {
en : 'aaaaa1111',
de : 'bbbbbbbbbb'
}
Try this:
Model.findOneAndUpdate({fieldA : val.fieldA},{
"$set": {
"fieldA": val.fieldA,
"fieldB.en": val.fieldB.en
}
})
In your solution you update document completny with other one. To update only specific fields you must specify this fields in "$set" object
I resolve this by finding the document first and editing de object manually.
/* Recursive function to update manually an object */
const update = (obj, newValues) => {
Object.entries(newValues).forEach( ([key, value]) => {
if(typeof value === 'object'){
update(obj[key], value);
} else {
obj[key] = value;
}
});
}
/* Find document, update and save */
const infoToUpdate = {};
const doc = await Model.findOne({ field: valueToFind });
if (doc) {
object.update(doc, infoToUpdate);
doc.save();
}
You have to change the object passed to findOneAndUpdate() so that you don't pass fieldB as an object, only the fields to update.
It can be done with something like this:
let val = {
fieldA: 'aaaaa11',
fieldB: {
en: 'aaaaa1111',
},
};
if (val.fieldB) {
const newFieldB = Object.entries(val.fieldB).reduce(
(a, [key, value]) => ({ ...a, ['fieldB.' + key]: value }),
{}
);
delete val.fieldB;
val = { ...val, ...newFieldB };
}
Model.findOneAndUpdate({fieldA : val.fieldA},{ $set : val})
With that, the value of val passed to findOneAndUpdate() is:
{
fieldA: 'aaaaa11',
'fieldB.en': 'aaaaa1111',
}
Instead of:
{
fieldA: 'aaaaa11',
fieldB: {
en: 'aaaaa1111',
},
}
... and attributes of fieldB that you didn't specify in val but that were in your DB will not get overridden.

insert and insertOne not a function and update not creating mongo ID

I thought I could read my way to this solution, but I cant see what im doing wrong.
Here is my model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var inspectSchema = new Schema({
_id: Object, // Mongo ID
property: String, // Property ID
room: String, // The room Name
item: Array // The Items text
});
module.exports = mongoose.model('inspectModel', inspectSchema, 'inspect');
And here is where I try to insert or insertOne
var inspectModel = require('../../models/inspectModel');
var inspectTable = mongoose.model('inspectModel');
inspectTable.insert(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
},
function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
})
I tried
inspectTable.insert
inspectModel.insert
inspectTable.insertOne
inspectModel.insertOne
No matter what I always get
TypeError: inspectTable.insert is not a function
I also tried just update with { upsert: true } but then the mongo ID becomes null.
Any ideas?
The method you're looking for is create:
inspectTable.create(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
}, ...
However, your schema definition of _id: Object is likely wrong. Just leave any definition of _id out of your schema and it will use the default ObjectId, which is likely what you want.
You can try this
var insert_table = new inspectTable(
{
"property" : inspectRecord.property,
"room" : inspectRecord.room,
"item" : inspectRecord.item
});
insert_table.save(function (err, res) {
if (err) { return reject({err:true, err:"addInspect ERROR" + err}) }
else {
show("=====RESOLVE addInspect=====")
return resolve();
}
});

dynamically add fields to find() mongodb

Hi i am working with mongoDB , i am trying to crate a dynamic object and pass as an argument to the find()
my object is like this
Library
var search = {};
if(data.orderId) {
search["_id"] = { $in: data.orderId.split(",") } ;
}if(data.path) {
search["stops.districtId"] = data.path;
}if(data.special) {
search["special.option"] = { $in: data.special.split(",") } ;
}if(data.userInfo) {
search["UserId"] = data.userInfo;
}
then i will pass my search objet to the query like this
Model
var col = db.collection( CustomerOrderModel.collection() );
col.find(
{
serviceType:data.serviceType,
**search**
}
).skip(data.skip).limit(data.limit).sort(data.sort).toArray(function(err, res) {
if (err) {
reject( err );
} else {
resolve( res );
}
});
the problem here is when i console.log my search object i can see
'special.option': { '$in': [ 'ROUND_TRIP' ] } }
my $in is wrapped with quotes . so my query doesn't work .
if i directly type "special.option": { $in: [ 'ROUND_TRIP' ] } } in my query it is working correctly .
i m trying to built this search object because i have multiple fields to search with complex logic . i don't want to do these in my
model , so i wil create the search object in my library .
is there any possible ways to this , thanks in advance .
You should make the search object part of the query by adding the extra filters into the search object. As you are currently doing
col.find({
serviceType:data.serviceType,
search
})
this is interprated as
col.find({
serviceType:data.serviceType,
{ 'special.option': { '$in': [ 'ROUND_TRIP' ] } }
})
You should be able to add the serviceType filter to your existing search object using the square bracket notation as follows:
search["serviceType"] = data.serviceType;
then you can pass that object in your query:
var col = db.collection( CustomerOrderModel.collection() );
search["serviceType"] = data.serviceType;
col.find(search)
.skip(data.skip)
.limit(data.limit)
.sort(data.sort)
.toArray(function(err, res) {
if (err) { reject( err ); }
else { resolve( res ); }
});
That is not the problem.
console.log({ "special.option": { $in: [ 'ROUND_TRIP' ] } });
gives
{ 'special.option': { '$in': [ 'ROUND_TRIP' ] } }
so this is correct.
In your code you just write **search** in the most critical part, but try this:
search["serviceType"] = data.serviceType;
col.find( search )

deleting specific json element - mongodb

i want to delete one specific point out of my db
// DB layout
{
id: 9243
email: asd#asd.asd
//stuff
point0:{
//stuff
point1:{
//stuff
point2:{
//stuff (dynamic)
}
}
}
}
now i want to delete point2 out of my db - without! knowing whats inside of it
//actual state of dev:
collection.update({'email': mail}, { $pull: elem }, function(err){
//tested:
elem = { "point0.point1" : "point2" }
elem = "point0.point1.point2"
elem = { "point0.point1.point2" : "" }
pullAll
... etc
have you tried using $unset to remove the value point2?
collection.update({'email' : mail}, {$unset : {'point0.point1.point2' : 0}}, function (err) {})

I can not get mongoose/node.js to retrieve data properly. What am I doing wrong?

I am trying to get node.js to write to the console the data in the table, my other tables work.
Whenever I try I get the following output:
NO ERROR!
QUERY:{"emitted":{"complete":[[]]},"_events":{}}
Am I missing something in the Schema definition?
Any help would be appreciated.
- Eric
The following is from the mongo shell :
> db.userAssessments.find({})
{ "accountId" : "509683edcb884b0000000001", "created" : ISODate("2013-01-12T03:31:20.723Z"), "_id" : ObjectId("50f0d9084469766bb7000001") }
This is my js:
var userAssessmentsSchema = new mongoose.Schema({
accountId : String,
created : Date,
id: String
});
ANALYZER.userAssessments = mongoose.model('userAssessments', userAssessmentsSchema);
ANALYZER.analyzeAssessment = function() {
var query = ANALYZER.userAssessments.find({}).exec(function(err, ass) {
if (!err) {
console.log("NO ERROR!");
console.log("QUERY:" + JSON.stringify(query));
} else {
console.log("ERROR!");
}
});
};
The result of the find query is passed to the exec callback as the second parameter (ass in your code). The return value you assign to query is the Promise object returned from exec.
UPDATE
Your other problem is that Mongoose pluralizes and lower-cases the model name to derive the collection name if you don't provide one. To make it use the userAssessments collection instead of userassessments you need to provide that collection name in the mongoose.model call.
So your code should be like this instead:
ANALYZER.userAssessments = mongoose.model(
'userAssessments', userAssessmentsSchema, 'userAssessments');
ANALYZER.analyzeAssessment = function() {
ANALYZER.userAssessments.find({}).exec(function(err, ass) {
if (!err) {
console.log("NO ERROR!");
console.log("QUERY:" + JSON.stringify(ass));
} else {
console.log("ERROR!");
}
});
};

Resources