How to use $push inside $set in mongoose? - node.js

I'm using express-restify-mongoose library to have rest endpoints agaist mongoose.
I have schema looks like this:
const BookSchema = new Schema(
{
name: { type: String },
items: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Book' }],
}
);
So I send http patch request: { name: 'blabla' } and it change the name as expect.
But when I want to add item to items array like { items: ["5dd138199f6ecb3990360328"] } its replace the entire object (with one 5dd138199f6ecb399036032d item).
After I digging in the source code I see here the function uses findOneAndUpdate and $set.
So my question is there is any way to use $push or any function/property in the $set value?
I can't add to this library, but maybe there is any workaround solution here?

I think the closest solution in mongoose is to use Set Elements in Arrays:
"items.1": "5dd138199f6ecb3990360355"
Which will add to array, but you have to pass the position.

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.

Mongoose : How to find documents in which fields match an ObjectId or a string?

This is mongoose DataModel in NodeJs
product: {type: mongoose.Schema.Types.ObjectId, ref: 'products', required: true}
But in DB, this field is having multiple type of values in documents, have String and ObjectId
I'm querying this in mongoose
{
$or: [
{
"product": "55c21eced3f8bf3f54a760cf"
}
,
{
"product": mongoose.Types.ObjectId("55c21eced3f8bf3f54a760cf")
}
]
}
But this is only fetching the documents which have that field stored as ObjectId.
Is there any way that it can fetch all the documents having both type of values either String OR ObjectId?
Help is much appreciated. Thanks
There is a schema in Mongoose, so when you query a document, it will search it by this schema type. If you change the model's product type to "string", it will fetch only documents with string IDs.
Even if there is a way to fetch either a string OR ObjectId, it's smelly to me to have such inconsistency.
I've encountered the same problem, so the solution was to standardize all documents by running a script to update them.
db.products.find().forEach(function(product) {
db.products.update({ type: product.type},{
$set:{ type: ObjectId(data.type)}
});
});
The only problem I see there is if this type field is actually an _id field. _id fields in MongoDB are immutable and they can't be updated. If that is your case, you can simply create a new document with the same (but parsed) id and remove the old one.
This is what I did: (in Robomongo)
db.getCollection('products').find().forEach(
function(doc){
var newDoc = doc;
newDoc._id = ObjectId(doc._id);
db.getCollection('products').insert(newDoc);
}
)
Then delete all documents, which id is a string:
db.getCollection('products').find().forEach(
function(doc){
db.getCollection('products').remove({_id: {$regex: ""}})
}
)
There is another way to do this. If we Update the type to Mixed then it will fetch all the documents with each type, either String or ObjectId
Define this in your Schema
mongoose.Schema.Types.Mixed
Like
product: {type: mongoose.Schema.Types.Mixed, required: true}

Ways to remove sub-documents in Mongoose

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?

Mongoose: Find reference documents by id before inserting a doc

Is there a way for checking if a reference document id exists in the array field of its "parent" model?
Imagine you know the objectId you want to check if exists because you don't want duplicates and also want to avoid that an error was thrown when trying to insert it.
I would like to know if there is an elegant and simple way as the method mongoose provides when working with subdocuments: var doc = car._components.id(theComponentIdIWantToCheck)
In this case it is a reference document:
Example:
// Car.js
var CarSchema = new Schema({
name: String,
description: String,
_components: [ { type: Schema.Types.ObjectId, ref: 'Component'},]
});

Resources