Is there a way to store a document then get an updated value of it at a later date without needing to query and populate again?
const someDocument = await SomeModel.findOne({...}).populate(...);
// store a reference to it for use
const props = {
document: someDocument,
...
}
// at a later time
await props.document.getLatest() <-- update and populate in place?
As describe here,
You can define your own custom document instance methods by add functions on the schema level.
example taken from mongoose doc:
// define a schema
const animalSchema = new Schema({ name: String, type: String });
// assign a function to the "methods" object of our animalSchema
animalSchema.methods.findSimilarTypes = function(cb) {
return mongoose.model('Animal').find({ type: this.type }, cb);
};
const Animal = mongoose.model('Animal', animalSchema);
const dog = new Animal({ type: 'dog' });
dog.findSimilarTypes((err, dogs) => {
console.log(dogs); // woof
});
This is the only way I can think of doing what you want - add a function that populate.
another thing that might help: you can create a pre hook on 'find' and add populate in it
Related
I´m using mongoose and I need to find a model name from a model instance.
In one part of the code I have:
const schema = new mongoose.Schema({
name: {
type: String,
required: true
},
phone: {
type: String,
required: true
}
}
const schema = new mongoose.Schema('MyData', schema);
let instance = new this({
name: 'Pete',
phone: '123'
});
Ths instance variable is passed around in my code. Later I need to find out instance name, but I´m no sure if there is a way to do it, something like:
let instanceName = getInstanceName(instance); <== Expects 'MyData' to be returned
Is that possible using mongoose ?
I realized I had a model not an instance of a model so I needed to use something else.
If you have a model, you can get the name as below:
const model = mongoose.model("TestModel", schema);
const collectionName = model.collection.collectionName;
If you have a specific item/instance of the model:
const instance = new model({...});
const collectionName = instance.constructor.modelName
as Hannah posted.
The name of the model can be accessed using this instance.constructor.modelName.
In my case I was looking for how to get a discriminator model name from a mongoose model, and the suggested solutions didn't work:
const PerformanceResult = DropDown.discriminator('PerformanceResult', new db.Schema({
name: { type: String, required: true }
}))
export default PerformanceResult
console.log(PerformanceResult.constructor.modelName) // undefined
console.log(PerformanceResult.collection.collectionName) // DropDown (parent name)
you can use this:
console.log(PerformanceResult.modelName) // PerformanceResult
mongoose version: "^5.11.8"
I have a child component, in which, after button press it pass a form field to a father component. I have to pass this fields as query Params to an API GET /valuation/ that require more or less 20 optional parameters, in which the name differs from Input fields.
I created a temporary object res inside the father function accept in which I iterate the field . Still I can't figure how to pass this parameter inside the object res, using multiple if is dirty code.
for example
Function in father component
accept(form:any){
const req: any = {};
if(form.name)
req.user = form.name
if(form.address)
req.clusterAddress = form.address
... and so on x 20 times
this.requestService.getRequest(req).subscribe(
(response) => {
this.getRequest(response);
}, (error) => {
console.error(error);
}
}
As you can see this is not a viable option, what I can use to take dynamically the query param names?
You can use a map to store information about which property from the form maps to which property on your res object and then iterate through the keys, check for the presence of the value and assign:
const formToResMap: { [key: string]: string } = {
name: 'name',
address: 'clusterAddress',
// ...
};
accept(form: any) {
const req = Object.keys(formToResMap).reduce((acc, key) => {
if (form[key]) {
acc[formToResMap[key]] = form[key];
}
return acc;
}, {});
console.log(req);
}
I just updated to normalizr version 3.1.x so I can utilize the denormalization. Though they've significantly changed their API. I'm having trouble transferring my schemas over.
import { normalize, Schema, arrayOf, valuesOf } from 'normalizr';
const usersSchema = new Schema('users')
const photosSchema = new Schema('photos')
const phonesSchema = new Schema('phones')
photosSchema.define({
users: arrayOf(usersSchema)
})
phonesSchema.define({
users: arrayOf(usersSchema)
})
usersSchema.define({
photos: valuesOf(photosSchema),
phones: valuesOf(phonesSchema)
})
That was my existing schema for users. I was also using the redux-normalizr middleware inside my redux action, so I connected the schema to my action like this:
import { usersSchema } from '../normalizrSchemas/usersSchemas.js'
import { arrayOf } from 'normalizr'
export function getUsers(data) {
return {
type: 'GET_USERS',
payload: data,
meta: {
schema : arrayOf(usersSchema)
}
}
}
This was my first attempt to convert the schema over. It doesn't seem you can call schema.Array the same way you could using arrayOf, so I thought I needed to move the array call into the schema.
import { schema } from 'normalizr';
const photos = new schema.Entity('photos')
const phones = new schema.Entity('phones')
const user = new schema.Entity('user', {
photos: [photos],
phones: [phones]
})
const users= new schema.Array('users', user)
export { users }
the action is the same, but i've removed wrapping the schema in arrayOf. All of the users data is just getting dumped into results without any normalization. The data is a list of user object, and each object contains an id, which normalizr should pick up. I'm struggling to figure out how to get normalizr the identify that it's an array of object I think.
schema.Array does not accept a key string name (docs). The first argument should be the schema definition. So instead of
const users= new schema.Array('users', user)
You should use:
const users = new schema.Array(user)
Or, you could just use the shorthand for an array of a single entity type:
const users = [ user ];
From the Firebase note:
Given a single key path like alanisawesome, updateChildren() only updates data at the first child level, and any data passed in beyond the first child level is a treated as a setValue() operation. Multi-path behavior allows longer paths (like alanisawesome/nickname) to be used without overwriting data. This is why the first example differs from the second example.
I am trying to use a single function createOrUpdateData(object) in my code. In case of update, it updates first level children properly, but if I have nested object passed, then it deletes all other properties of that nested object.
Here's the code:
function saveUserDetails(email,object){
var hashedEmail = Utilities.getHashCode(email);
var userRef = ref.child(hashedEmail);
return $q(function(resolve,reject){
return userRef.update(object, function(error){
if(error){
reject(error);
}else{
resolve("Updated successfully!");
}
});
});
}
So if I pass:
{
name: 'Rohan Dalvi',
externalLinks: {
website: 'mywebsite'
}
}
Then it will delete other properties inside externalLinks object. Is there a cleaner and simpler way of avoiding this?
In short, how do I make sure nested objects are only updated and that data is not deleted.
You can use multi-path updates.
var userRef = ref.child(hashedEmail);
var updateObject = {
name: 'Rohan Dalvi',
"externalLinks/website": 'mywebsite'
};
userRef.update(updateObject);
By using the "externalLinks/website" syntax in the object literal it will treat the nested path as an update and not a set for the nested object. This keeps nested data from being deleted.
This question provides a more recent solution that works with cloud firestore.
Rather than using "/", one may use "." instead:
var userRef = ref.child(hashedEmail);
var updateObject = {
name: 'Rohan Dalvi',
"externalLinks.website": 'mywebsite'
};
userRef.update(updateObject);
To update nested object/map/dictionary in firebase database, you can use Firestore.Encoder to class/struct that is Codable.
Here is a Swift code example:
Models:
import FirebaseFirestore
import FirebaseFirestoreSwift
// UserDetails Model
class UserDetailsModel: Codable {
let name: String,
externalLinks: ExternalLinkModel
}
// UserDetails Model
class ExternalLinkModel: Codable {
let website: String
}
Calling Firebase:
import FirebaseFirestore
import FirebaseFirestoreSwift
let firestoreEncoder = Firestore.Encoder()
let fields: [String: Any] = [
// using firestore encoder to convert object to firebase map
"externalLinks": try! firestoreEncoder.encode(externalLinkModel)
]
db.collection(path)
.document(userId)
.updateData(fields, completion: { error in
...
})
Is there a way to add custom instance methods to a mongoose schema after it has already been "exported".
For example, if I have a schema:
module.exports = function(app, db, config) {
var MySchema = new Schema({ name: String });
MySchema.methods.doIt = function() { console.log("I DID IT!"); }
db.model("MySchema", MySchema);
}
Then I want to add new methods to the schema dynamically after it has already been loaded into the mongoose model object.
MySchema = db.model('MySchema');
var obj = new MySchema({name: "robocop"});
var myNewMethod = function() { console.log(this.name); }
// Do Magic here to add the myNewMethod to object.
obj.myNewMethod();
Did You Even Try?
I have already tried to just add it to the mongoose model object, however this produces errors saying the schema objects do not have the method I just added.
MySchema = db.model('MySchema');
MySchema.schema.methods.myNewMethod = function() { console.log(this.name); }
db.model('MySchema', MySchema);
console.log(MySchema.schema.methods); // This shows my method was added!
...
var obj = new MySchema({name: "robocop"});
obj.myNewMethod(); //ERROR: YOUR METHOD DOESN'T EXIST!
Caveat coder. It is possible, and whether or not it's a good idea is left as an exercise for the reader.
Your schema is of course affected by the schema object, not any particular instance of your model. Thus, if you want to modify the schema, you'll need to have access to the schema itself.
Here's an example:
var mongoose = require('mongoose')
, db = mongoose.connect("mongodb://localhost/sandbox_development")
var schema = new mongoose.Schema({
blurb: String
})
var model = mongoose.model('thing', schema)
var instance = new model({blurb: 'this is an instance!'})
instance.save(function(err) {
if (err) console.log("problem saving instance")
schema.add({other: String}) // teh secretz
var otherInstance = new model({blurb: 'and I am dynamic', other: 'i am new!'})
otherInstance.save(function(err) {
if (err) console.log("problem saving other instance", err)
process.exit(0)
})
})
Notice the call to schema.add which Schema calls internally when you make a new one.