I'm trying to update multiple nested object in mongoose using a certain if condition and the object I want to update (or create if it doesn't exist) is located multiple layers deep into my wrapper schema. My simplified structure looks like this:
const C = mongoose.Schema({
data: String
})
const B = mongoose.Schema({
createdAt: Date,
tasks: [C]
})
const A = mongoose.Schema({
client_id: String,
objects: [B]
})
const AModel = mongoose.model("A", A)
First I need to find a specific A model by it's client_id;
Then find a B model from the objects array with certain createdAt value (e.g. the one with the date matching today's date) or create an empty B model if nothing matching my condition was found;
Push into tasks array of the found (or a newly created) B object a C object with a certain condition (e.g. if there's C no object with the same data field).
I don't think it's a good way to do this via basic js code as my models could store a vast amount of data and it doesn't sound good to modify all that data every time I need to insert a single object so I'm looking for a pure mongoose-query solution.
So far I've came up with something like this but I'm not sure how to properly locate and update nested objects inside my B model.
await AModel.updateOne(
{ client_id: clientId },
{
$push: {
objects: { $where: this.createdAt.toDateString() == today.toDateString() },
},
},
{ upsert: true, setDefaultsOnInsert: true }
)
Related
I apologize in advance for the very basic question. I have a javascript page on which I create a number of objects, and assign those objects certain properties. What I would like to do is create an array whose elements are all and only those objects which have a certain property. I know how to create (e.g.) an array whose elements are all and only those DOM elements with a certain class; but I can't figure out how to do the parallel thing with javascript objects with a certain property.
I recognize that I could do this manually via an array literal. What I am looking for is a way to generate the array automatically, so that when new javascript objects with the relevant property are added, they are automatically added to the array.
For example, if I have
const firstconstant = {
type: "A",
};
const secondconstant = {
type: "B",
};
const thirdconstant = {
type: "A",
};
etc. I'd like a way of generating an array whose elements are all of the objects with type "A". Thanks for any help with this.
There's no point for declaring a new variable for every new object, that's the reason arrays were invented - so you don't have to type firstconstant, secondconstant, thirdconstant etc.
First declare an array with all the objects (and add them here):
const objects = [
{ type: "A" },
{ type: "B" },
{ type: "A" },
];
And then you can use the .filter method to filter out the objects that don't match:
const filtered = objects.filter(object => object.type === "A");
This is a document from my profiles collection:
{
_id: ObjectId("5f2ba3a43feccd0004b8698c")
userID: "238906554584137728",
serverID: "533691583845892100",
username: "W.M.K",
money: 15775,
__v: 4,
items: [...],
serverName: "W-15i: Overworld",
gladium: 7959.33,
stocks: [{
_id: {...},
stockID: "605b26d309a48348e05d88c9",
name: "GOOGL",
amount: 1,
desc: "Alphabet Inc's (Google) Stock."
}]
}
I'm using const profile = await Profile.findOne({userID: userID, 'stocks.stockName': stock.name})
EDIT: For one stock, it's as easy as profile.stocks[0].amount -=1. But when I have multiple stocks, how do I get the amount and manipulate it like amount -= 1?
there are few ways you can go through an array of objects in mongoose... you can map through the array, you can also use dot notation in an update. Either way one thing you'll need to do is mark the document modified because mongo doesn't detect changes in arrays of objects. To do this, make the changes and then use the markModified() function on the document. It takes a parameter of the array field name that was modified. in this case.... profile.markModified('stocks')
This is done after changes and before the save.
You can use dot notation with mongoose and you can also iterate through the array via map or forEach
The benefit of using map is that you can double it up with .filter() to filter the array for certain stocks
As already stated by Jeremy, it is basically a matter of array manipulations.
Here is one example:
for(let i = 0; i < profile.stocks.length; i++) {
profile.stocks[i].amount -= 1;
}
If you just want to update the profile on your database, you could also look into some very advanced mongodb querys (I think it's called "aggregation"), but that is probably overkill.
When I use Document.get on a nested document it returns undefined, where as when I use Document.get with the full path it works
Example:
const PostsSchema = new mongoose.Schema({
author: {
name: String
}
});
const Posts = mongoose.model('posts', PostsSchema);
const doc = new Posts({
author: {
name: 'Harry'
}
});
console.log(doc.get('author.name'));
// "Harry"
console.log(doc.author.get('name'));
// undefined
I believe the difference between the two ways you've presented is related to the difference between Subdocuments and nested paths as explained in the official doc: Subdocuments versus Nested Paths
Comparing to the examples given, 'author' is not a Subdocuments of the 'Posts', it's a property defined in the Schema, therefore, the correct syntax, as presented in the official doc Document.prototype.get(), is to pass the path as a string (as the first way you typed):
doc.get(path,[type],[options])
path «String»
[type] «Schema|String|Number|Buffer|*» optionally specify a type for on-the-fly attributes
[options] «Object»
[options.virtuals=false] «Boolean» Apply virtuals before getting this path
[options.getters=true] «Boolean» If false, skip applying getters and just get the raw value
I'm looking for a way to store objects in a collection and identify them by UUID, then query the collection to get an object by UUID. The closest example I can think of is the Dictionary collection in .NET. Is there a recommended functionality in Dojo for this?
There is no equivalent in dojo, and even when the dojo/store/Memory module is not meant for this purpose, you can use it in some way as a collection, check this out:
require(["dojo/store/Memory"], function(Memory){
var someData = [
{id:1, name:"One"},
{id:2, name:"Two"}
];
store = new Memory({
idProperty: "id", //define the id property
data: someData
});
// Returns the object with an id of 1
store.get(1);
// Returns query results from the array that match the given query
store.query({name:"One"});
// Pass a function to do more complex querying
store.query(function(object){
return object.id > 1;
});
// Returns query results and sort by id
store.query({name:"One"}, {sort: [{attribute: "id"}]});
// store the object with the given identity
store.put({id:3, name:"Three"});
// delete the object
store.remove(3);
});
dojo has other types of store that may suit more to your case than the dojo/store/Memory. Here are some links to docs:
dojo/store/Memory
dojo/store/JsonRest
dojo/store/DataStore
dojo/store/Cache
Exist others, but this are the must commons
There is not such objects has Collection in JavaScript. But you could create your own Objects like below
var coll = { uid : "value" };
coll['uid2'] = "value2;
This can be accessed using
var a = coll['uid'];
This is the beauty of JavaScript.
I want to get references in mongoDB using nodejs/mongoose.
In the documentation I read that there are two options: Manual References or DBRefs.
Since they state, its recommended to use Manual References, I decided to set up a schema in the following way:
var schema = new mongoose.Schema({
name : String,
reference : mongoose.Schema.ObjectId
});
Question: If I retrieve an array of these objects from my collection, how do I resolve the references in a good practice way?
My Idea was to use Nimble and parallelize the necessary requests. I wanted to do something like
flow.parallel(functions, function() {
return result;
});
where I dynamically fill an array of functions
var functions = []
which I pass then to nimble.
(kind of this SO-question: Javascript Array of Functions)
Question: Is this practical? The array of functions-thing seems kind of not really the way to go to me. But I don't see any alternative, since nimble needs to be called with a static number of functions.
You can use Mongoose's support for reference population to efficiently follow references.
var schema = new mongoose.Schema({
name : String,
reference : { type: mongoose.Schema.ObjectId, ref: 'OtherModel' }
});
var MyModel = mongoose.model('MyModel', schema);
MyModel.find().populate('reference').exec(function(err, docs) {...});
In the above example, the reference field of each docs element gets populated with referenced doc.