How to update a object in mongodb via mongoose? - mongodb

I have mongoose schema as:
var Organization = new Schema({
name: String,
address: {
street : String,
city: String
}
}, { collection: 'organization' });
How do I update only street part of address for an organization via mongoose?

I can't find any docs that cover this simple case so I can see why you're having trouble. But it's as simple as using a $set with a key that uses dot notation to reference the embedded field:
OrganizationModel.update(
{name: 'Koka'},
{$set: {'address.street': 'new street name'}},
callback);

Now you can update directly .
OrganizationModel.update(
{name: 'Koka'},
{'address.street': 'new street name'},
callback);

Using Document set also, specified properties can be updated. With this approach, we can use "save" which validates the data also.
doc.set({
path : value
, path2 : {
path : value
}
}
Example: Update Product schema using Document set and save.
// Update the product
let productToUpdate = await Product.findById(req.params.id);
if (!productToUpdate) {
throw new NotFoundError();
}
productToUpdate.set({title:"New Title"});
await productToUpdate.save();
Note - This can be used to update the multiple and nested properties also.

Related

Mongoose subdocuments return different ID every time

I have a model Franchise that has another Schema Employee as its subdocuments for a field. The structure is as follows.
Franchise.js
const Franchise = new mongoose.Schema(
{
franchiseName: String,
address: String,
managers: [Employee]
});
export default mongoose.model(
"Franchise",
Franchise
);
Employee.js
const Employee = new mongoose.Schema(
{
name: String,
email: String,
phoneNo: Number,
password: String,
});
export default Employee;
The issue I am facing is with every query to Franchise, it returns a new _id for the objects in managers field. Is there any way to make it constant ?
For instance, I am running a simple findById on Franchise and store it in franchise variable.
and then I console.log(franchise.managers).
It prints different IDs each time the query is run.
[
{
_id: new ObjectId("61925d2697852574eb0ba9ab"),
name: 'Franchise Manager 1',
email: 'franchise1#sfc.com',
phoneNo: 1234567890,
}
]
Second time the query is run:
[
{
_id: new ObjectId("61925ba8130aca93a7dd3dbc"),
name: 'Franchise Manager 1',
email: 'franchise1#sfc.com',
phoneNo: 1234567890
}
]
As you can see, the employee is the same, however it has different Id for each call. Kindly help.
Thanks.
Alright, I figured it out. The issue is that there was no _id stored in the database for existing data of managers. The Employee schema was added later on, so as the _id was not present in the database only, a new one was being generated each time.

What's the best way to update a Map/Dictionary which is part of a MongoDb document?

I'm new to MongoDb so I'm not sure what's the best approach regarding the following:
I have a MongoDb document which contains multiple fields, including a map/dictionary.
e.g. -> priceHistogram:
rents {
_id:"1234",
city:"London",
currentPrice:"500",
priceHistogram: {"14-02-2021" : "500"}
}
I would like to update the currentPrice field with the latest price but also add to the price histogram taday's date and the price'; e.g. if today's price would be 600, I would like to obtain the following:
rents {
_id:"1234",
city:"London",
currentPrice:"600",
priceHistogram: {"14-02-2021" : "500", "20-02-2021" ": "600"}
}
What would be the most efficient MongoDb function/approach allowing me to achieve this (everything else remains the same - _id/city)?
Thank you
Not sure how your schema looks like, I will assume that the schema looks similar to:
const rentsSchema = mongoose.Schema(
{
city: { type: String, required: true },
currentPrice: {type: String},
priceHistogram: {type: Map, of:String}
}
)
const rents = mongoose.model('Rents', histSchema);
And the update:
rents.updateOne({city:"London"},{
currentPrice:"600",
"priceHistogram.24-02-2021": "600"
})
Since as I have understood Map is another way to add arbitrary properties.

How to populate with a second model if first one is empty

I've three models,
modelA, modelB and ModelC
ModelC's data is here
{
"_id" : ObjectId("586e1661d9903c6027a3b47c"),
"RefModel" : "modelA",
"RefId" : ObjectId("57f37f18517f72bc09ee7632")
},
{
"_id" : ObjectId("586e1661d9903c6027a3b47c"),
"RefModel" : "modelB",
"RefId" : ObjectId("57f37f18517f72bc09ee7698")
},
Howto write a populate query for ModelC, to populate with RefId .
it should populate with modelA or modelB which RefModel refers.
I've tried with
ModelC.find({})
.populate({ path: 'RefId', model: 'modelA' })
.populate({ path: 'RefId', model: 'modelB' })
But taking only the last model.
modelC schema.
new mongoose.Schema({
RefModel: String,
RefId:{ type: Schema.ObjectId}});
I could do it with aggregate, but preferring populate.
Fields' names in your database and schema are very confusing, let me explain on more clear example.
Suppose you have 3 models: User, Article and Comment. Article and Comment belongs only to single User. User can have multiple comments and articles (As you shown in your example).
(More efficient and reccommending way). Store comments and articles ids in User model like:
comments: [{ id: '..', ref: Comment }],
articles: [{ id: '..', ref: Article }]
and populate your document:
User.find({})
.populate('comments')
.populate('articles');
Store User id in Comment and Article models like
user: { id: '...', ref: User }
and use mongoose-reverse-populate module for population, for example for comments model:
var reversePopulate = require('mongoose-reverse-populate');
User.find().exec(function(err, users) {
var opts = {
modelArray: users,
storeWhere: "comments",
arrayPop: true,
mongooseModel: Comments,
idField: "user"
}
reversePopulate(opts, function(err, popUsers) {
// populated users will be populated with comments under .comments property
});
});
Also you dont need to keep RefModel in your database, only in schema.
Here, you can try and populate it inside the callback of find itself.
Try this:
ModelC.find({}).exec(function(err,modelC){
//find returns an array of Object, you will have to populate each Object individually.
var modelCObjects =[];
modelC.forEach(function(tempModelC){
//populate via the Model
ModelC.populate(tempModelC,{path : tempModelC.refId , model :tempModelC.refModel},function(err2,newModelC){
//handle newModelC however you want
//Push it into array of modelC Objects
modelCObjects.push(newModelC);
});
//OR
//Populate directly on the resultObject <-im not so sure about this
tempModelC.populate({path : tempModelC.refId , model :tempModelC.refModel},function(err2,newModelC){
//Push it into array of modelC Objects
modelCObjects.push(newModelC);
})
});
//here you have modelCObjects -> Array of populated modelC Objects
});
Please make sure to handle the errors.

Does using dbref do anything more than just storing an `id`

My Mongoose schema:
// set up the schema
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
},
And my controller code:
CategorySub.create({
name : req.body.name,
_category_main : req.body.category_main
}, function(err, data){
An entry in my db:
{
"_id": "54dd163434d78ae58f6b1a69",
"name": "Snacks",
"_category_main": "54dcf4a71dfecb4d86ddcb87",
"__v": 0
},
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for references?
Also, instead of passing the entire JSON object in the request - req.body.category_main, why not just pass and id and change my schema to this?:
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
},
In short, Yes.
The below schema definition is an example of Manual references.
var CategorySubSchema = new Schema({
name: { type: String },
category_main_id : { type: String }
}
where,
you save the _id field of one document in another document as a
reference. Then your application can run a second query to return the
related data. These references are simple and sufficient for most use
cases.
In this case, we need to write explicit application code to fetch the referred document and resolve the reference. Since the driver that we use wouldn't know about the collection in which the referred document is present nor the database in which the referred document is present.
When you define the schema as below, this is an example of storing the details of the referred document .(Database references)
var CategorySubSchema = new Schema({
name: { type: String },
_category_main : { type: String, ref: 'CategoryMain' }
}
They include the name of the collection, and in some cases the
database name, in addition to the value from the _id field.
These details allow various drivers to resolve the references by themselves, since the name of the collection and the database(optional) of the referred document would be contained in the document itself, rather than we writing explicit application code to resolve the references.
So I used an underscore, because I was following an example. Does this mean anything to the database or is it just convention for
references?
Using underscore in the _id field is a valid naming convention, but mongoDb doesn't explicitly mention about the naming convention of other fields which are used to resolve references. You could just use any other field name as long as it conforms to this.

Sails 10.x waterline: What attribute type to use for Mongo objectID

sailsjs: I am trying to define a model. I would like to add a property vendorID. The type would be the monogdb objectID from the vendor collection.
Something like for a store model:
module.exports ={
attributes :{
vendorId : { type: <Monog ObjectId>}, <-- this would be a FK to the vendor Collection
storeName: {type: 'string'}
....
}
Waterline docu says:
The following attribute types are currently available:
string
text
integer
float
date
time
datetime
boolean
binary
array
json
So what do I pick?
Thanks
You should look into SailsJS associations. With waterline you shouldn't need to deal directly with id types. Just create an attribute that points to another collection via the model or collection properties.
Here's a simple example from the Sails/Waterline docs.
//Pet.js - A Pet may only have a single user
module.exports = {
attributes: {
name:'STRING',
color:'STRING',
owner:{
model:'user'
}
}
}
//User.js - A user may have multiple pets
module.exports = {
attributes: {
name:'STRING',
age:'INTEGER',
pets:{
collection: 'pet',
via: 'owner'
}
}
}
The _id is created automatically for you by Waterline you don't have to do this.