Ways to remove sub-documents in Mongoose - node.js

I am currently trying to design a schema structure with mongoose which looks like the following:
var hubSchema = new mongoose.Schema({
//some other properties
dataStream: {
dataType: String,
dataPoints: [{
createdAt: { type: Date, expires: '7d'}
data: {}
}],
storeStrategy: {
type: String,
enum: storeStrategies
}
},
});
The mongoose API docs say that:
Sub-documents enjoy all the same features as normal documents. The
only difference is that they are not saved individually, they are
saved whenever their top-level parent document is saved.
I want dataPoints to be an array of sub-documents and each sub-document should have TTL set just as a normal document. Having said that, I found out from other posts that it is not possible to set 'expires' for sub-documents. So my question is: Should I create a separate model for dataPoints and store a references here or I should implement some custom strategy for deleting sub-documents keeping this kind of structure?

Related

How to insert Array of objects in mongoDB?

I am very new to MONGO DB so please bear with me.I am having a problem my array of objects is not working properly .
Here is my schema
const playerSchema = new mongoose.Schema({
name: String,
stats :{
wins:Number,
losses:Number,
xp:Number
},
achievement:[
{
name:String,
date: String
}
] });
Here is my document
const fluffy = new playerModel({
"name":"nic raboy",
"stats":{
"wins":5,
"losses":10,
"xp":300
},
"achievements":[
{"name":"Massive XP","date" :"25-08-21"},
{"name":"instant loss","date":"24-08-21"}
]
});
however in mongodb atlas its only showing array...and i cant see the objects inside...
SCREENSHOT
Your schema is correct, it seems your input is wrong,
In schema definition you named it achievement, whereas in input document it is achievements. Correct this everything will work as you expected.
Explanation
The schema is expecting achievement and you inserted achievements, that is why it is shown as an empty array in the database. To avoids this kind of typos in the future, use the required flag.
const playerSchema = new mongoose.Schema({
name: String,
stats: {
wins: Number,
losses: Number,
xp: Number
},
achievements: [
{
name: {
type: String,
required : true,
},
date: {
type: String,
required : true, // required informs for missing fields
}
}
]
})
Refer this link for more on validation
You can use insertMany see the doc here.
Of course, a while loop should work find calling multiple times insertOne, though I advise you to use the insertMany() method.
If you're new to MongoDB, I strongly encourage you to have a look at MongoDB University's MongoDB basics course as well as the MongoDB for JavaScript Developers course.

Mongoose: Define schema for a complex field containing objectIds

I've a mongoDB record field called taxonomies which is an object and each of it's property contains an array of single/multiple mongo objectId which reference to other documents. The property keys are dynamic and cannot be hard-coded.
"taxonomies": {
"job-region": [
"5ef4ad0b7f6b7c001df895b7"
],
"salary-slabs": [
"5ef4ad657f6b7c001df895ca",
"5ef4ad657f6b7c001df895cc",
"5ef4ad657f6b7c001df895cd"
],
"experience": []
},
Given the above document format I want to define mongoose schema definition in such way so that I can use the .populate() method on the query afterwards. I've tried following schema definition but since the field is not a simple string of a single ID, it does not work with populate.
// Schema Definition
const JobSchema = new mongoose.Schema({
taxonomies: {
type: mongoose.Schema.ObjectId,
ref: "Taxonomy",
required: true,
},
});
Any idea how to define it so I can use the populate() method? Any help would be appreciated.

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 embedded document as key-val array

I'm trying to use mongoose to represent an association between 3 schemas:
Schema1: {
//fields
}
Schema2: {
//fields
}
Scehma3: {
//fields
- [Scehma1:Scehma2] - collection of key-val elements
where the key is a ref to schema1 and val is ref to scehma2
}
Does mongoose support this king of association without creating a schema4?
You can't create ambiguous keys in mongoose because its whole purpose is to handle your document structure for you. What you can do, however, is create an array of objects.
Schema4: {
schemaRefs: [{
refToSchema1: {type: mongoose.Types.ObjectId, ref: 'Schema1'},
refToSchema2: {type: mongoose.Types.ObjectId, ref: 'Schema2'}
}]
}
For future reference it's far easier to understand your question when you provide real examples rather than false names. Even if you falsify your example (e.g. some relationship between restaurants and customers or something) it's much easier to understand the relationship you're trying to make.

Resources