Mongoose searching on array subdocument ObjectId not working - node.js

This is honestly driving me crazy. Here's the problem:
I'm running the following query in Mongoose:
s.findSubdocument=function(uid, cb)
{
this.model('User').find({"flwng._id":uid.toString()}).select('flwng').exec(cb);
}
on the following User Schema:
var userSchema= new mongoose.Schema(
{
uname:{type:String, index:{sparse:true, unique:true, dropDups:true}}, //the username
email:String,
pwd:{type:String},
flwng:[{_id : {type : mongoose.Schema.ObjectId},uname : String}], //_id of users I am following
flwrsz:Number,
flwngsz:Number,
feedsz:Number,
}, {j: 1});//j:1 means guarantee it is written to the journal.
userSchema.set('autoIndex', true);
userSchema.index({"fid":1}, {sparse:true, unique:true, dropDups:true});
userSchema.index({"flwng._id" : 1});
Where uid="53c4f16c431247694f0000a3" ==> but I get an empty array back :(
When I run the same exact query in the mongo shell:
db.users.find({"flwng._id":"53c4f16c431247694f0000a3"});
I get the right set of results back. I tried with and without an index and schema on "flwng._id", I tried to drop the index, reIndex and I'm now running out of ideas. Am I doing something wrong with Mongoose?
Any help would be appreciated - thanks!
Henri

There's a mismatch between your existing documents in mongodb and your schema. Your data has records where flwng._id is a String, which is why you get results in the mongo shell. But your mongoose schema defines that as an ObjectId, so when you query with mongoose, mongoose casts your string value to an ObjectId and the query doesn't match. Either write a migration to fix your existing data or update your schema to match your data in terms of String vs ObjectId data type and things should start working through mongoose.

Related

mongoose model refuses to update array of objects inside array of objects

I've a schema for a store inventory. The location has locationcategories array in the schema and inside that array, I have items[] array.
My issue is updating this items[] inside the locationcategories[]. I use the mongodb shell to update that array (using updateOne()) and it works (update my items[] inside locationcategories[]) but when I do it using mongoose model ("Locations") it doesn't update, in my console, it just shows { n: 1, nModified: 0, ok: 1 } which indicate that everything was found but didn't modify anything. When I check the db, it doesn't have any new items added.
Here is code I use in mongoshell which updates items[] inside locationcategories[]
db.locations.updateOne({"locationname" :"My Town", "locationcategories":{"$elemMatch":{"categoryname": "Media"}}},{$push:{"locationcategories.$.items": {"test":"test"}}})
In my application server route (expressjs) I enter the following:
Location.updateOne(
{ "locationname": "My Town", "locationcategories": {"$elemMatch":{"categoryname": "Media"}}},
{$push: {"locationcategories.$.items": {"test":"test"}}},
{new : true, upsert: true },
function (error, results) {
console.log("findByIdAndUpdate results :", results);
}
);
my mongooose schema-model:
var Schema = mongoose.Schema;
var locationSchema = new Schema({
locationname: String,
locationdescription: String,
locationcategories: [{ categoryorder: Number, categoryname: String,
categorydescription: String, items[{itemname: String }]}],
items: [{categoryid : String, itemorder: Number, itemname: String, itemdescription: String, itemprice: Number }],
created_at: Date
});
var Location = mongoose.model('Location', locationSchema);
export default Location;
I'm using mognodb version 4.02
Model.updateOne should work but it is not adding anything to my db. I read many of the stackoverflow.com issues but I couldn't find anything that indicate an issue except this old question from years ago which he had an issue updating array inside array. I find it hard to believe that there is an issue and no one addressed it after all those years but I might be wrong.
If the mongo shell execute and add to db correctly, it leads me to believe that the mongoose model or schema are responsible for the issue or my updateOne() code is wrong.
Any idea why?
Got it. So I changed items inside the locationcategories[] to categoryItems[] and it works.
The .$ operator looks for the first array with the name items which was items outside but I was posting the data to the model's first array.
Make sure you name the arrays in your model with unique names and point the $push to the correct array.
Also upgrded mongodb from version 4.0 to the latest one 4.41.

Non-existing field in Mongodb document appears in mongoose findById() result

I'm somewhat new in what is related to Mongoose and I came to this behaviour I consider as strange. The document returned by Mongoose has fields that are not present in the actual MongoDb document, and seem to be added by Mongoose based on the schema.
I use a schema similar to this (this one is simplified) :
const ProfessionalSchema = new mongoose.Schema({
product: {
details: [{
_id: false,
id: String, // UUID
name: String,
prestations: [{
_id: false,
id: String, // UUID
name: String,
price: Number,
}],
}],
},
[...]
My document as shown in Mongodb with mongo CLI utility doesn't have a product field.
What I don't understand is why the result of Professional.findById().exec() returns a document with a product:{details[]} field. I expect not to have that field in the Mongoose returned result, since it is not present in the original MongoDb document.
The Mongoose documentation found https://mongoosejs.com/docs/guide.html (Schema and Model paragraph) didn't help.
My business logic would require that field not to be present, instead of being forced by the schema. Is this achievable ?
Try taking a look at the default option. You could e.g. default your product to null and then, in your business logic, handle the "product is null" case rather than the "product field does not exist" case.
As for why this is happening, it's because you're dealing with a schema. If the field doesn't exist on the document, it's going to be auto-populated. The whole point of a schema is to ensure consistency of your document structure.

Weird mongoose behavior when viewing ObjectIds?

When viewing a sub-document with Robomongo I see something like this:
"views" : [
ObjectId("53a478431275cf0f3d91e27d"),
ObjectId("53a478431275cf0f3d91e27d")
]
But when I pull down the object through Mongoose into node.js, I see something like this:
views:
[ { _bsontype: 'ObjectID',
id: 'T\u001aôj#Ü«m¢©Ö',
viewDate: '2015-07-07T23:21:32.259Z' } ]
Yes, the schema is a little different, and I'm trying to write a script to remediate the data into the new format.
The schema is currently
views: [{view:{type: Schema.Types.ObjectId, ref: 'users'},viewDate:{type: Date, default: Date.now}}],
But
A) Why does the view object look all messed up in the latter, and
B) How can I get what I see in Robomongo? (Answered. See edit)
EDIT: Question B is answered. If I do .lean() to my query, then I'll be able to get it back as a non-mongoose object and it'll look how I expect it to look. So that just leaves question A
I managed to reproduce this.
First, you declared a schema similar to this:
views : { type : Schema.Types.ObjectId, ref : 'users' }
You created and wrote documents to the database using that schema.
Then you changed the schema to your current:
views: [{
view : { type: Schema.Types.ObjectId, ref: 'users' },
viewDate : { type: Date, default: Date.now }
}]
Using that schema, you are reading the documents that you wrote to the database using the first schema.
Those schema are fundamentally different: the first is stored as a single ObjectId in the database (the term "subdocument" is a bit confusing, because in Mongoose, subdocuments are documents that are stored with their parent document; the method you're using is called "population" in Mongoose-speak), but the second schema makes views an array of documents that have two properties (view, which is stored as an ObjectId and viewData which is a date).
This confuses Mongoose because it tries to apply the second schema to documents that were written using the first schema, and because of that, it's showing the internal representation of an ObjectId object instead of a stringified version of it.
This also explains why .lean() shows the correct results, because that tells Mongoose to return raw documents (as they are stored in the database) instead of trying to convert them according to the schema.

MongoDB, Mongoose, and composite _id

New to Mongodb & Mongoose.js.
I have created the following schema & model:
var schema = new Schema({
_id: {part1: String, part2: Number},
name: String
});
mongoose.model('myDoc', schema);
I can save this, and when I view it on the mongo command line, it looks fine.
However in mongoose when I do:
myDoc.find({}, function(err, recs) {
var rec = recs[0];
console.log('----' + JSON.stringify(rec));
});
I get my object printed out, but with the following exception: Cast to ObjectId failed for value "[object Object]" at path "_id"
I've seen a few explanations, but I don't understand what I'm doing wrong, and how I need to fix it.
According to mongodb documentation the _id can be bson-type. What am I doing wrong? Isn't {part1: String, part2: Number} a bson?
According to this post from the Mongoose author, compound _id fields aren't yet supported by Mongoose.

Mongoose nodejs find not working correctly

so I'm doing a mongoose find and I've defined collections etc and it all works fine EXCEPT when I try to do a find by a value.
var searchID = req.user.id;
console.log(searchID);
Locations.find({userid: '541f69e7fd4c3b07108c92c0'}, function(err, location) {
if (err) return console.error(err);
console.log(location);
});
the userid is a property which is the ID of the user that created it. The find doesnt work in mongo console either.
Any ideas? I can do finds by the actual _id of the location or any other value.
As Neil Lunn commented, your problem is almost certainly your schema not being correct. Once your mongoose schema clearly defines the userid property as being of type mongoose.Schema.Types.ObjectId, mongoose will start casting your string value from the query to a proper ObjectId instance before sending it to mongodb, and thus the query will start matching documents and you'll see results.
{userid: {type: mongoose.Schema.Types.ObjectId, ref: 'Users'}}

Resources