Associative array with mongoose schema? - node.js

Is it considered bad practice to use associative arrays in mongodb? I'm curious as to why mongoose doesn't seem to provide this in its Schema definition.

If by "associative array", you mean "Object", that works fine. You can use just regular old "Object" or you can specify specific properties or you can use "mongoose.Schema.Types.Mixed" to allow varying types.
{
//regular old javascript/json data types
created: Date,
//this works just fine
statistics: Object,
//or you can specify the shape of the object
address: {state: String, line1: String},
//for the extra features you get with a true subdocument
nested: [SomeOtherMongooseSchema],
//Could be array, boolean, number, whatever. Can vary with each document.
grabBag: mongoose.Schema.Types.Mixed
}

Considering you use mongoose version > 5.1.0
As specified here in the documentation: https://mongoosejs.com/docs/schematypes.html#maps
You can use Map this way to specify an associative array :
myAssociativeArray: {
type: Map,
of: String
}
By the way i don't know if you can specify the key type with this syntax

Related

Mongoose Query with Dynamic Key that also contains the "and" operator

So I'm trying to query my MongoDB database using mongoose to fetch documents that have a specific family AND a specific analysis ID at the same time. Here is an example of the document structure:
_id: ObjectId("62b2fb397fda9ba6fe24aa5c")
day: 1
family: "AUTOMOTIVE"
prediction: -233.99999999999892
analysis: ObjectId("629c86fc67cfee013c5bf147")
The problem I face in this case is that the name of the key of the family field is set dynamically and could therefore have any other name such as "product_family", "category", etc. This is why, in order to fetch documents with a dynamic key name, I have to use the where() and equals() operators like so:
// Get the key of the field that is set dyncamically.
let dynamicKey = req.body.dynamicKey;
// Perform a query using a dynamic key.
documents = await Model.find().where(dynamicKey).equals(req.body.value);
HOWEVER, my goal here is NOT to just fetch all the documents with the dynamic key, but rather to fetch the documents that have BOTH the dynamic key name AND ALSO a specific analysis Id.
Had the family field NOT been dynamic, I could have simply used a query like so:
documents = await Model.find({
$and: [{analysis: req.body.analysis_id}, {family: req.body.value}]
});
but this does not seem possible in this case since the keys inside the find() operator are mere text strings and not variables. I also tried using the following queries with no luck:
documents = await Model.find().where(dynamicKey).equals(req.body.value).where('analysis').equals(req.body.analysis_id);
documents = await Model.find().where(dynamicKey).equals(req.body.value).where('analysis').equals(req.body.analysis_id);
Can somebody please help?
As #rickhg12hs mentioned in the comments, part of the answer is to use the [] brackets to specify your dynamic key like so:
await Model.find({[dynamicKey]: req.body.value, analysis: req.body.analysis_id});
I also found out that another query that can work is this:
await Model.find({analysis:req.body.analysis_id}).where(dynamicKey).equals(req.body.value);
However, it seems that for either of these solutions to work you also need to set your schema's strict mode to "false", since we are working with a dynamic key value.
Example:
var predictionSchema = new mongoose.Schema({
day: {
type: Number,
required: true
},
prediction: {
type: Number,
required: true
},
analysis: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Analysis', // Reference the Analysis Schema
required: true
}
}, { strict: false });

Indexing with Mongoose

I was reading the mongoose docs about indexing and want to find out whether there is a difference between field level indexing and schema level indexing. They mention that "defining indexes at the schema level is necessary when creating compound indexes." Are there any other reasons why I might choose one over the other or it is just a preference?
const animalSchema = new Schema({
name: String,
type: String,
tags: { type: [String], index: true } // field level
});
animalSchema.index({ name: 1, type: -1 }); // schema level
When developing your indexing strategy you should have a deep understanding of your application’s queries. Before you build indexes, map out the types of queries you will run so that you can build indexes that reference those fields.
for example you have a query just find based on one field like name so you can indexing name in field level but if you have a query that find based on name and tag so you should indexing name and tag together for this situation you should use indexing in schema level

Set mongoose field as type of either String or Number

I have a field example in my database, which I want it to be either Number or String:
export const mySch = new mongoose.Schema({
example: {
type: String,
},
});
How can I do it?
There is a type in mongoose Schema.Types.Mixed which can be used to save values of any type in the given field. However, I haven't yet found a way to restrict it to just a particular subset of types e.g String and Number.
Here is the link if you want to study in detail yourself: https://mongoosejs.com/docs/schematypes.html#mixed.
You can use Mongoose Discriminator.
https://mongoosejs.com/docs/discriminators.html

Is it bad practice to set mongodb object id to a 'String' instead of 'Schema.Types.ObjectId'?

I want to know if this can affect performance or other important matters in terms of functionality especially when finding documents in a mongodb collection
I have done this
var ComputerArticleSchema = mongoose.Schema({
_id: {
type: String,
required: true
},
its commonly done like this
_id: {
type: Schema.Types.ObjectId,
required: true
},
Not performance but when you have more than two model and they have their association then how can you link between them. So, it is necessary. And you don't have to manually define(write) like you did, mongodb automatically create the _id.
_id is created automatically!
If you are referencing other table use 'table_id' (or some other key name) and give type as Schema.Types.ObjectId or Schema.ObjectId.
const ObjectId = Schema.ObjectId;
user_id: { type: ObjectId, ref: 'User' }
Storing strings rather than ObjectIds does hurt performance.
ObjectIds are smaller than the equivalent strings (they are a 12 byte binary value rather than a 24 character UTF-8 string value), so they take up less space in memory.
Mongo is really fast when indexes & documents are in the working set (i.e. in memory) so by lowering the data footprint, you're able to make sure that more documents stay in memory. This is especially important because the id fields that you're talking about are often included in indexes.

how to use the attribute type like 'array' and 'json' in sails

Sails have support very convenient model througth Waterline, and I have used the 'array' attribute type in the way storing many string, but now I want to store more complex object, Although I can store the raw data in mongo by 'array' type, I don't know if it is safe and I want define the object type in the array, like mongoose's style. for example, I need a model "Products" and I want define it as a 'array' but the object stored in the array only model "Book", what I can do like this, but I don't think it works.
module.exports = {
products : {
type : 'array',
Book : {
name : 'string',
price : 'integer'
}
}
}
So, any suggestion about use of the 'array' and 'json' is very appreciated, thanks so much!
I don't think that the array type is going to work the way you want it to. What you're looking for is associations which will be available in SailsJS 0.10 (which you can get via git right now). The array attribute type for MySQL and PostgreSQL it will only stringify the array and store it as text in the database then it will parse the field when returning the value.
source

Resources