Ember.js - Error while loading route: TypeError: Cannot set property 'store' of undefined - rest

I'm getting the following error in my Ember.js app.
Error while processing route: books Cannot set property 'store' of undefined TypeError: Cannot set property 'store' of undefined
at DS.Store.Ember.Object.extend.modelFor (http://localhost:8080/js/libs/ember-data.js:2986:19)
at DS.Store.Ember.Object.extend.recordForId (http://localhost:8080/js/libs/ember-data.js:2437:17)
at deserializeRecordId (http://localhost:8080/js/libs/ember-data.js:3355:23)
at deserializeRecordIds (http://localhost:8080/js/libs/ember-data.js:3369:5)
at http://localhost:8080/js/libs/ember-data.js:3335:7
at http://localhost:8080/js/libs/ember-data.js:7117:16
at http://localhost:8080/js/libs/ember.js:14899:20
at Object.OrderedSet.forEach (http://localhost:8080/js/libs/ember.js:14741:14)
at Object.Map.forEach (http://localhost:8080/js/libs/ember.js:14897:14)
at Function.DS.Model.reopenClass.eachRelationship (http://localhost:8080/js/libs/ember-data.js:7116:38)
I'm using
ember.js version 1.7.1 and
ember-data.js version 1.0.0-beta.5.
I have the following project:
window.App = Ember.Application.create();
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:8080'
});
App.Router.map(function() {
this.resource('books', { path: '/' });
});
App.BooksRoute = Ember.Route.extend({
model: function() {
return this.store.find('book');
}
});
App.Author = DS.Model.extend({
firstname: DS.attr('string'),
lastname: DS.attr('string')
});
App.Book = DS.Model.extend({
title: DS.attr('string'),
authors: DS.hasMany('author')
});
and the following is my JSON response to http://localhost:8080/books.
{
"books":
[
{
"id": 0,
"authors":
[
{
"id": 0,
"firstname": "Andrzej",
"lastname": "Sapkowski"
}
],
"title": "Zaklínač I: Poslední přání"
},
...
]
}
When I remove the Author model and the authors relationship declaration, the application works fine.
The error message I'm getting doesn't reveal the cause and according to what I've found on the Internet, my code seems to be ok.
What's the problem?

Wow, I can't believe I didn't notice this, but your data isn't formatted properly. It should look something like this:
{
"books": [{}, {}, {}],
"authors": [{}, {}, {}]
}
This is explained in the REST adapter guide.

Related

How to fix constructor error in GraphQL Mutation with Mongoose Schema [duplicate]

This question already has answers here:
Mongoose TypeError: User is not a constructor
(1 answer)
TypeError: User is not a constructor
(6 answers)
Closed 3 years ago.
Having a lot of trouble with a GraphQL mutation Mongoose error for validating if a user is new or existing in MongoDB. Per the code below the error message is "message": "User is not a constructor".
A similar issue is here, and I redefined the variable below given each method in the solution to that linked issue with similar errors - only change in error was due to lacking constructor such as when I used other methods like append the error is "User is undefined".
CodeSandbox with all the code: https://codesandbox.io/s/apollo-server-sh19t?fontsize=14
The code in question is:
var userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
trim: true
},
password: {
type: String,
required: true,
trim: true
},
avatar: {
type: String
},
joinDate: {
type: Date,
default: Date.now
},
favorites: {
type: [mongoose.Schema.Types.ObjectId],
required: true,
ref: "Post"
}
});
// compile model
var User = mongoose.model("User", userSchema);
var getUserModel = function() {
return mongoose.model("User", userSchema);
};
Mutation: {
signupUser: async (_, { username, email, password }, { User }) => {
let user = await getUserModel().findOne({ username });
if (user) {
throw new Error("Please choose another username");
}
const newUser = await new User({
username,
email,
password
}).save();
return newUser;
}
}
};
The full error is:
{
"errors": [
{
"message": "User is not a constructor",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"signupUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: User is not a constructor",
" at signupUser (/xxx/xxx/xxx/servers.js:175:29)",
" at process._tickCallback (internal/process/next_tick.js:68:7)"
]
}
}
}
],
"data": null
}
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"signupUser"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read property 'create' of undefined",
" at signupUser (/xxxx/xxxx/xxx/servers.js:175:38)"
Any assistance to this issue would be greatly appreciated.
That TypeError is thrown any time you try to use the new keyword with something that's not a constructing, including an undefined value. Even if you define a User variable outside of the constructor, you're still shadowing that variable because you're destructuring the context parameter and declaring a User variable that way. If you're not passing the User model to your context correctly, attempting to get the value from the context will result in the value being undefined. Either fix the context or don't unnecessarily destructure it.

Update's request for mongodb [duplicate]

I have a document structure that is deeply nested, like this:
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{ level: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{ level: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
I'm trying to update the collection to insert a new config, that looks like this:
newdata = {
config: "Custom 1",
variables: [{ x: 111, y:2222, z:3333}]
}
I'm trying something like this in mongo (in Python):
db.myCollection.update({"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.$.configs.$": newData}}
)
I'm getting "Cannot apply the positional operator without a corresponding query field containing an array" error though. What is the proper way to do this in mongo? This is mongo v2.4.1.
Unfortunately, you can't use the $ operator more than once per key, so you have to use numeric values for the rest. As in:
db.myCollection.update({
"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.0.configs.0": newData}}
)
MongoDB's support for updating nested arrays is poor. So you're best off avoiding their use if you need to update the data frequently, and consider using multiple collections instead.
One possibility: make forecasts its own collection, and assuming you have a fixed set of level values, make level an object instead of an array:
{
_id: 123,
parentId: 1,
name: "Forecast 1",
levels: {
proven: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
likely: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
}
}
Then you can update it using:
db.myCollection.update({
_id: 123,
'levels.proven.configs.config': 'Custom 1'
},
{ $set: { 'levels.proven.configs.$': newData }}
)
Managed to solve it with using mongoose:
All you need to know is the '_id's of all of the sub-document in the chain (mongoose automatically create '_id' for each sub-document).
for example -
SchemaName.findById(_id, function (e, data) {
if (e) console.log(e);
data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
// or if you want to change more then one field -
//=> var t = data.sub1.id(_id1).sub2.id(_id2);
//=> t.field = req.body.something;
data.save();
});
More about the sub-document _id method in mongoose documentation.
explanation:_id is for the SchemaName, _id1 for sub1 and _id2 for sub2 - you can keep chaining like that.
*You don't have to use findById method, but it's seem to me the most convenient as you need to know the rest of the '_id's anyway.
MongoDB has introduced ArrayFilters to tackle this issue in Version 3.5.2 and later.
New in version 3.6.
Starting in MongoDB 3.6, when updating an array field, you can specify
arrayFilters that determine which array elements to update.
[https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]
Let's say the Schema design as follows :
var ProfileSchema = new Schema({
name: String,
albums: [{
tour_name: String,
images: [{
title: String,
image: String
}]
}]
});
And Document created looks like this :
{
"_id": "1",
"albums": [{
"images": [
{
"title": "t1",
"url": "url1"
},
{
"title": "t2",
"url": "url2"
}
],
"tour_name": "london-trip"
},
{
"images": [.........]:
}]
}
Say I want to update the "url" of an image.
Given - "document id", "tour_name" and "title"
For this the update query :
Profiles.update({_id : req.body.id},
{
$set: {
'albums.$[i].images.$[j].title': req.body.new_name
}
},
{
arrayFilters: [
{
"i.tour_name": req.body.tour_name, "j.image": req.body.new_name // tour_name - current tour name, new_name - new tour name
}]
})
.then(function (resp) {
console.log(resp)
res.json({status: 'success', resp});
}).catch(function (err) {
console.log(err);
res.status(500).json('Failed');
})
This is a very OLD bug in MongoDB
https://jira.mongodb.org/browse/SERVER-831
I was facing same kind of problem today, and after lot of exploring on google/stackoverflow/github, I figured arrayFilters are the best solution to this problem. Which would work with mongo 3.6 and above.
This link finally saved my day: https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html
const OrganizationInformationSchema = mongoose.Schema({
user: {
_id: String,
name: String
},
organizations: [{
name: {
type: String,
unique: true,
sparse: true
},
rosters: [{
name: {
type: String
},
designation: {
type: String
}
}]
}]
}, {
timestamps: true
});
And using mongoose in express, updating the name of roster of given id.
const mongoose = require('mongoose');
const ControllerModel = require('../models/organizations.model.js');
module.exports = {
// Find one record from database and update.
findOneRosterAndUpdate: (req, res, next) => {
ControllerModel.updateOne({}, {
$set: {
"organizations.$[].rosters.$[i].name": req.body.name
}
}, {
arrayFilters: [
{ "i._id": mongoose.Types.ObjectId(req.params.id) }
]
}).then(response => {
res.send(response);
}).catch(err => {
res.status(500).send({
message: "Failed! record cannot be updated.",
err
});
});
}
}
It's fixed.
https://jira.mongodb.org/browse/SERVER-831
But this feature is available starting with the MongoDB 3.5.12 development version.
Note: This question asked on Aug 11 2013 and it's resolved on Aug 11 2017
Given how MongoDB doesn't appear to provide a good mechanism for this, I find it prudent to use mongoose to simply extract the element from the mongo collection using .findOne(...), run a for-loop search on its relevant subelements (seeking by say ObjectID), modify that JSON, then do Schema.markModified('your.subdocument'); Schema.save(); It's probably not efficient, but it is very simple and works fine.
I searched about this for about 5 hours and finally found the best and easiest solution:
HOW TO UPDATE NESTED SUB-DOCUMENTS IN MONGO DB
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{
levelid:1221
levelname: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{
levelid:1221
levelname: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]}
Query:
db.weather.updateOne({
"_id": ObjectId("1"), //this is level O select
"forecasts": {
"$elemMatch": {
"forecast_id": ObjectId("123"), //this is level one select
"levels.levelid": ObjectId("1221") // this is level to select
}
}
},
{
"$set": {
"forecasts.$[outer].levels.$[inner].levelname": "New proven",
}
},
{
"arrayFilters": [
{ "outer.forecast_id": ObjectId("123") },
{ "inner.levelid": ObjectId("1221") }
]
}).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
Sharing my lessons learned. I faced the same requirement recently where i need to update a nested array item.
My structure is as follows
{
"main": {
"id": "ID_001",
"name": "Fred flinstone Inc"
},
"types": [
{
"typeId": "TYPE1",
"locations": [
{
"name": "Sydney",
"units": [
{
"unitId": "PHG_BTG1"
}
]
},
{
"name": "Brisbane",
"units": [
{
"unitId": "PHG_KTN1"
},
{
"unitId": "PHG_KTN2"
}
]
}
]
}
]
}
My requirement is to add some fields in a specific units[].
My solution is first to find the index of the nested array item (say foundUnitIdx)
The two techniques I used are
use the $set keyword
specify the dynamic field in $set using the [] syntax
query = {
"locations.units.unitId": "PHG_KTN2"
};
var updateItem = {
$set: {
["locations.$.units."+ foundUnitIdx]: unitItem
}
};
var result = collection.update(
query,
updateItem,
{
upsert: true
}
);
Hope this helps others. :)
EASY SOLUTION FOR Mongodb 3.2+
https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
I had a similar situation and solved it like this. I was using mongoose, but it should still work in vanilla MongoDB. Hope it's useful to someone.
const MyModel = require('./model.js')
const query = {id: 1}
// First get the doc
MyModel.findOne(query, (error, doc) => {
// Do some mutations
doc.foo.bar.etc = 'some new value'
// Pass in the mutated doc and replace
MyModel.replaceOne(query, doc, (error, newDoc) => {
console.log('It worked!')
})
}
Depending on your use case, you might be able to skip the initial findOne()
Okkk.we can update our nested subdocument in mongodb.this is our schema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
solution for this schema
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{"post.$.comment.0.detail.time":"aajtk"}},
function(err,data){
//data is updated
})

Error while setting up Extjs Rest Proxy Create function

I am using Rest proxy in Extjs Model as:
Ext.define('ThemeApp.model.peopleModel', {
extend: 'Ext.data.Model', fields: [
{ name: 'userId' },
{ name: 'title' },
{ name: 'body'}
],
proxy: {
type: 'rest',
format: 'json',
limitParam:"",
filterParam: "",
startParam:'',
pageParam:'',
url:'http://jsonplaceholder.typicode.com/posts/1',
api: {
read : 'http://jsonplaceholder.typicode.com/posts/1',
create: 'http://httpbin.org/post'},
headers: {'Content-Type': "application/json" },
reader: {
type: 'json',
//rootProperty:'issues'
},
writer: {
type: 'json'
}
In my view I am calling create function as:
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
As I am testing everything on http://jsonplaceholder.typicode.com/ so I am expecting that code will work cause when I test GET and POST functionality via Postman utility everything works fine.
Can anyone point out my error?
I found my mistake.
In the following code I was not setting the correct name of my model, as it won't be "Posts"
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
Also if you are trying with http://jsonplaceholder.typicode.com/ you are not supposed to send ID in the post request.

Extjs PUT url with wrong id

I'm new to senach and ExtJs, and I'm trying to read and write json data. getting the data is already working, but I can't write changed data back to the server.
I'm using a ExtJs 4.2.
I configured one URL in the RestProxy url: /animals/dogs/
GET http://example.com/animals/dogs
PUThttp://example.com/animals/dogs/{id}
Get is working as expected. But the PUT URL is:
example.com/animals/dogs/project.model.dogs-3?dc435453...
The id also contains the model name. How can I change this to the id like above?
This is the store:
Ext.define('project.store.MyJsonStore', {
extend: 'Ext.data.Store',
requires: [
'project.model.dogs',
'Ext.data.proxy.Rest',
'Ext.data.reader.Json'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
autoLoad: true,
autoSync: true,
model: 'project.model.dogs',
storeId: 'MyJsonStore',
proxy: {
type: 'rest',
limitParam: 'count',
url: '/animals/dogs,
reader: {
type: 'json',
idProperty: 'id',
root: 'data'
}
}
}, cfg)]);
}
});
This is the model:
Ext.define('project.model.dogs', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.Field'
],
clientIdProperty: 'id',
fields: [
{
name: 'id',
type: 'int'
},
{
name: 'type',
type: 'string'
}
]
});
GET Respones: (reader root is data)
{
"success": true,
"data":
[
{
"id": 1,
"type": "Some Type",
"url": "/animals/dogs/1"
},
{
"id": 2,
"type": "Some other Type",
"url": "/animals/dogs/2"
},
]
}
The PUT urls look like:
example.com/animals/dogs/project.model.dogs-3?dc...
example.com/animals/dogs/project.model.dogs-7?dc...
example.com/animals/dogs/project.model.dogs-8?dc...
The numbers 3, 7, 8 are the id's, so extjs recognizes the id property in the model.
Regards,
Sencha Beginner

Mongodb update deeply nested subdocument

I have a document structure that is deeply nested, like this:
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{ level: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{ level: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
I'm trying to update the collection to insert a new config, that looks like this:
newdata = {
config: "Custom 1",
variables: [{ x: 111, y:2222, z:3333}]
}
I'm trying something like this in mongo (in Python):
db.myCollection.update({"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.$.configs.$": newData}}
)
I'm getting "Cannot apply the positional operator without a corresponding query field containing an array" error though. What is the proper way to do this in mongo? This is mongo v2.4.1.
Unfortunately, you can't use the $ operator more than once per key, so you have to use numeric values for the rest. As in:
db.myCollection.update({
"id": 1,
"forecasts.forecast-id": 123,
"forecasts.levels.level": "proven",
"forecasts.levels.configs.config": "Custom 1"
},
{"$set": {"forecasts.$.levels.0.configs.0": newData}}
)
MongoDB's support for updating nested arrays is poor. So you're best off avoiding their use if you need to update the data frequently, and consider using multiple collections instead.
One possibility: make forecasts its own collection, and assuming you have a fixed set of level values, make level an object instead of an array:
{
_id: 123,
parentId: 1,
name: "Forecast 1",
levels: {
proven: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
likely: {
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
}
}
Then you can update it using:
db.myCollection.update({
_id: 123,
'levels.proven.configs.config': 'Custom 1'
},
{ $set: { 'levels.proven.configs.$': newData }}
)
Managed to solve it with using mongoose:
All you need to know is the '_id's of all of the sub-document in the chain (mongoose automatically create '_id' for each sub-document).
for example -
SchemaName.findById(_id, function (e, data) {
if (e) console.log(e);
data.sub1.id(_id1).sub2.id(_id2).field = req.body.something;
// or if you want to change more then one field -
//=> var t = data.sub1.id(_id1).sub2.id(_id2);
//=> t.field = req.body.something;
data.save();
});
More about the sub-document _id method in mongoose documentation.
explanation:_id is for the SchemaName, _id1 for sub1 and _id2 for sub2 - you can keep chaining like that.
*You don't have to use findById method, but it's seem to me the most convenient as you need to know the rest of the '_id's anyway.
MongoDB has introduced ArrayFilters to tackle this issue in Version 3.5.2 and later.
New in version 3.6.
Starting in MongoDB 3.6, when updating an array field, you can specify
arrayFilters that determine which array elements to update.
[https://docs.mongodb.com/manual/reference/method/db.collection.update/#specify-arrayfilters-for-an-array-update-operations][1]
Let's say the Schema design as follows :
var ProfileSchema = new Schema({
name: String,
albums: [{
tour_name: String,
images: [{
title: String,
image: String
}]
}]
});
And Document created looks like this :
{
"_id": "1",
"albums": [{
"images": [
{
"title": "t1",
"url": "url1"
},
{
"title": "t2",
"url": "url2"
}
],
"tour_name": "london-trip"
},
{
"images": [.........]:
}]
}
Say I want to update the "url" of an image.
Given - "document id", "tour_name" and "title"
For this the update query :
Profiles.update({_id : req.body.id},
{
$set: {
'albums.$[i].images.$[j].title': req.body.new_name
}
},
{
arrayFilters: [
{
"i.tour_name": req.body.tour_name, "j.image": req.body.new_name // tour_name - current tour name, new_name - new tour name
}]
})
.then(function (resp) {
console.log(resp)
res.json({status: 'success', resp});
}).catch(function (err) {
console.log(err);
res.status(500).json('Failed');
})
This is a very OLD bug in MongoDB
https://jira.mongodb.org/browse/SERVER-831
I was facing same kind of problem today, and after lot of exploring on google/stackoverflow/github, I figured arrayFilters are the best solution to this problem. Which would work with mongo 3.6 and above.
This link finally saved my day: https://thecodebarbarian.com/a-nodejs-perspective-on-mongodb-36-array-filters.html
const OrganizationInformationSchema = mongoose.Schema({
user: {
_id: String,
name: String
},
organizations: [{
name: {
type: String,
unique: true,
sparse: true
},
rosters: [{
name: {
type: String
},
designation: {
type: String
}
}]
}]
}, {
timestamps: true
});
And using mongoose in express, updating the name of roster of given id.
const mongoose = require('mongoose');
const ControllerModel = require('../models/organizations.model.js');
module.exports = {
// Find one record from database and update.
findOneRosterAndUpdate: (req, res, next) => {
ControllerModel.updateOne({}, {
$set: {
"organizations.$[].rosters.$[i].name": req.body.name
}
}, {
arrayFilters: [
{ "i._id": mongoose.Types.ObjectId(req.params.id) }
]
}).then(response => {
res.send(response);
}).catch(err => {
res.status(500).send({
message: "Failed! record cannot be updated.",
err
});
});
}
}
It's fixed.
https://jira.mongodb.org/browse/SERVER-831
But this feature is available starting with the MongoDB 3.5.12 development version.
Note: This question asked on Aug 11 2013 and it's resolved on Aug 11 2017
Given how MongoDB doesn't appear to provide a good mechanism for this, I find it prudent to use mongoose to simply extract the element from the mongo collection using .findOne(...), run a for-loop search on its relevant subelements (seeking by say ObjectID), modify that JSON, then do Schema.markModified('your.subdocument'); Schema.save(); It's probably not efficient, but it is very simple and works fine.
I searched about this for about 5 hours and finally found the best and easiest solution:
HOW TO UPDATE NESTED SUB-DOCUMENTS IN MONGO DB
{id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{
levelid:1221
levelname: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{
levelid:1221
levelname: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]}
Query:
db.weather.updateOne({
"_id": ObjectId("1"), //this is level O select
"forecasts": {
"$elemMatch": {
"forecast_id": ObjectId("123"), //this is level one select
"levels.levelid": ObjectId("1221") // this is level to select
}
}
},
{
"$set": {
"forecasts.$[outer].levels.$[inner].levelname": "New proven",
}
},
{
"arrayFilters": [
{ "outer.forecast_id": ObjectId("123") },
{ "inner.levelid": ObjectId("1221") }
]
}).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
Sharing my lessons learned. I faced the same requirement recently where i need to update a nested array item.
My structure is as follows
{
"main": {
"id": "ID_001",
"name": "Fred flinstone Inc"
},
"types": [
{
"typeId": "TYPE1",
"locations": [
{
"name": "Sydney",
"units": [
{
"unitId": "PHG_BTG1"
}
]
},
{
"name": "Brisbane",
"units": [
{
"unitId": "PHG_KTN1"
},
{
"unitId": "PHG_KTN2"
}
]
}
]
}
]
}
My requirement is to add some fields in a specific units[].
My solution is first to find the index of the nested array item (say foundUnitIdx)
The two techniques I used are
use the $set keyword
specify the dynamic field in $set using the [] syntax
query = {
"locations.units.unitId": "PHG_KTN2"
};
var updateItem = {
$set: {
["locations.$.units."+ foundUnitIdx]: unitItem
}
};
var result = collection.update(
query,
updateItem,
{
upsert: true
}
);
Hope this helps others. :)
EASY SOLUTION FOR Mongodb 3.2+
https://docs.mongodb.com/manual/reference/method/db.collection.replaceOne/
I had a similar situation and solved it like this. I was using mongoose, but it should still work in vanilla MongoDB. Hope it's useful to someone.
const MyModel = require('./model.js')
const query = {id: 1}
// First get the doc
MyModel.findOne(query, (error, doc) => {
// Do some mutations
doc.foo.bar.etc = 'some new value'
// Pass in the mutated doc and replace
MyModel.replaceOne(query, doc, (error, newDoc) => {
console.log('It worked!')
})
}
Depending on your use case, you might be able to skip the initial findOne()
Okkk.we can update our nested subdocument in mongodb.this is our schema.
var Post = new mongoose.Schema({
name:String,
post:[{
like:String,
comment:[{
date:String,
username:String,
detail:{
time:String,
day:String
}
}]
}]
})
solution for this schema
Test.update({"post._id":"58206a6aa7b5b99e32b7eb58"},
{$set:{"post.$.comment.0.detail.time":"aajtk"}},
function(err,data){
//data is updated
})