How to update and upsert documents in MongoDB (Mongoose). NodeJS - javascript

I have a service which get data from server using GET request. I repeat this request every 10 seconds and after every request I save these data to my database. My code attached below.
But I need filter my new data which I received from server to not repeat data in database. I read that I need to do update in my database with upset: true but I guess that I do something incorrect. Could you please help me with this task?
app.js code:
const Tenders = require('./libs/mongoose');
const request = require('request');
let url = `http://public.api.openprocurement.org/api/2.4/tenders?offset=${new Date().toISOString()}+02.00`;
function getTenders() {
request(url, { json: true }, (err, res, body) => {
if (err) {
return console.log(err);
}
url = `http://public.api.openprocurement.org/api/2.4/tenders?offset=${body.next_page.offset}`;
const tendersList = [];
let tendersData = new Tenders({ tenderId: String, tenderDate: String });
body.data.forEach((item) => {
tendersData = {
tenderId: item.id,
tenderDate: item.dateModified,
};
tendersList.push(tendersData);
});
Tenders.findAll({ tenderId: tendersData.tenderId }, (err, tenderId) => {
if (!tenderId) {
Tenders.insertMany(tendersList)
.then((item) => {
console.log('Saved to db');
})
.catch((err) => {
console.log(err);
});
} else {
console.log('Data is already in db');
}
});
});
}
getTenders();
setInterval(getTenders, 10000);
and just in case mongoose.js:
const mongoose = require('mongoose');
const config = require('../config');
mongoose.Promise = global.Promise;
mongoose.connect(
config.get('mongoose:uri'),
{ useMongoClient: true },
);
const tender = new mongoose.Schema({
tenderId: String,
tenderDate: String,
});
const Tenders = mongoose.model('Tenders', tender);
module.exports = Tenders;
I guess that my code with Tenders.find.... and Tenders.insertMany looks only for one item not all of them. So please, can you help me with inserting my first part of data and after that 'upsert' data in database with new data from server?

your insert/update logic can be simplified using update function with upsert flag true
Here is an implementation, (hope tenderId is indexed)
const TenderSchema = new Schema({ tenderId: String, tenderDate: String });
const Tender = mongoose.model('Tender', TenderSchema, 'tenders');
var tenders = [
{tenderId :'tender-1', tenderDate : '1-1-2018'},
{tenderId :'tender-2', tenderDate : '2-1-2018'},
{tenderId :'tender-3', tenderDate : '3-1-2018'},
{tenderId :'tender-2', tenderDate : '4-1-2018'},
{tenderId :'tender-1', tenderDate : '5-1-2018'},
{tenderId :'tender-2', tenderDate : '4-1-2018'}
];
for (var t of tenders){
Tender.update(
{'tenderId' : t.tenderId },
{$set : t},
{upsert : true, multi : true},
function(err, doc){
if(err) throw err;
console.log(doc);
}
)
}
collection
> db.tenders.find()
{ "_id" : ObjectId("5a5d87d8a5f292efd566d186"), "tenderId" : "tender-1", "__v" : 0, "tenderDate" : "5-1-2018" }
{ "_id" : ObjectId("5a5d87d8a5f292efd566d187"), "tenderId" : "tender-2", "__v" : 0, "tenderDate" : "4-1-2018" }
{ "_id" : ObjectId("5a5d87d8a5f292efd566d188"), "tenderId" : "tender-3", "__v" : 0, "tenderDate" : "3-1-2018" }
>
console log
saravana#ubuntu:~/node-mongoose$ node so4.js
`open()` is deprecated in mongoose >= 4.11.0, use `openUri()` instead, or set the `useMongoClient` option if using `connect()` or`createConnection()`. See http://mongoosejs.com/docs/connections.html#use-mongo-client
Mongoose: tenders.update({ tenderId: 'tender-1' }, { '$set': { tenderId: 'tender-1', tenderDate: '1-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
Mongoose: tenders.update({ tenderId: 'tender-2' }, { '$set': { tenderId: 'tender-2', tenderDate: '2-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
Mongoose: tenders.update({ tenderId: 'tender-3' }, { '$set': { tenderId: 'tender-3', tenderDate: '3-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
Mongoose: tenders.update({ tenderId: 'tender-2' }, { '$set': { tenderId: 'tender-2', tenderDate: '4-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
Mongoose: tenders.update({ tenderId: 'tender-1' }, { '$set': { tenderId: 'tender-1', tenderDate: '5-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
Mongoose: tenders.update({ tenderId: 'tender-2' }, { '$set': { tenderId: 'tender-2', tenderDate: '4-1-2018' }, '$setOnInsert': { __v: 0 } }, { multi: true, upsert: true })
{ n: 1, nModified: 1, ok: 1 }
{ n: 1, nModified: 1, ok: 1 }
{ n: 1, nModified: 0, ok: 1 }
{ n: 1, nModified: 1, ok: 1 }
{ n: 1, nModified: 1, ok: 1 }
{ n: 1, nModified: 0, ok: 1 }
^C
saravana#ubuntu:~/node-mongoose$

Related

How can I $push an item in two different fields, depending on the condition?

I'm trying to receive the user location and store it in the database. Also, the user can choose if he wants to save all his previous locations or not.
So I have created a boolean variable historicEnable: true/false.
So when the historicEnable is true, I want to push to historicLocation[] array in the UserSchema and if it is false, I want just to update currentLocation[] array in the UserSchema.
conntrollers/auth.js
exports.addLocation = asyncHandler(async (req, res, next) => {
const {phone, location, status, historicEnable} = req.body;
let theLocation;
if (historicEnable== true){
theLocation = await User.findOneAndUpdate(
{ phone },
{ $push:{ locationHistoric: location, statusHistoric: status }},
{ new: true }
)
} else if(historicEnable== false){
theLocation = await User.findOneAndUpdate(
{ phone },
{ location, status },
{ new: true }
)
}
res.status(200).json({
success: true,
msg: "A location as been created",
data: theLocation,
locationHistory: locationHistory
})
})
models/User.js
...
currentLocation: [
{
location: {
latitude: {type:Number},
longitude: {type:Number},
},
status: {
type: String
},
createdAt: {
type: Date,
default: Date.now,
}
}
],
historicLocation: [
{
locationHistoric: {
latitude: {type:Number},
longitude: {type:Number},
},
statusHistoric: {
type: String
},
createdAt: {
type: Date,
default: Date.now,
}
}
]
Also, not sure how to make the request body so the function works.
req.body
{
"phone": "+1234",
"historicEnable": true,
"loications": [
{
"location": {
"latitude": 25,
"longitude": 35
},
"status": "safe"
}
]
}
To sum up, if historicEnable is true, the data will be pushed in historicLocation, and if it false, to update the currentLocation.
How can I solve this?
You can use an update with an aggregation pipeline. If the historicEnable is known only on db level:
db.collection.update(
{phone: "+1234"},
[
{$addFields: {
location: [{location: {latitude: 25, longitude: 35}, status: "safe"}]
}
},
{
$set: {
historicLocation: {
$cond: [
{$eq: ["$historicEnable", true]},
{$concatArrays: ["$historicLocation", "$location"]},
"$historicLocation"
]
},
currentLocation: {
$cond: [
{$eq: ["$currentLocation", false]},
{$concatArrays: ["$currentLocation", "$location"]},
"$currentLocation"
]
}
}
},
{
$unset: "location"
}
])
See how it works on the playground example
If historicEnable is known from the input, you can do something like:
exports.addLocation = asyncHandler(async (req, res, next) => {
const phone = req.body.phone
const historicEnable= req.body.historicEnable
const locObj = req.body.location.locationHistoric[0];
locObj.createdAt = req.body.createdAt
const updateQuery = historicEnable ? { $push:{ locationHistoric: locObj}} : { $push:{ currentLocation: locObj}};
const theLocation = await User.findOneAndUpdate(
{ phone },
updateQuery,
{ new: true }
)
res.status(200).json({
success: true,
msg: "A location as been created",
data: theLocation,
locationHistory: locationHistory
})
})

Add new field to report - Script - NodeJS and MongoDB

I have to run a report from a script.
The script works fine
Need to add a new field that indicates if the user is admin or not.
I am not sure how to add that with a true or false condition.
Right now it is returning undefined or false.
The field in mongo database is this one:
mongo-database
var orderTotalsByUserId = {};
db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).forEach( d => orderTotalsByUserId[d._id.userId] = d.total )
var userIdsByOrders = db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).map( d => ObjectId(d._id.userId) )
var customers = {};
db.organizations.find().forEach(c => { customers[c._id.valueOf()] = c });
db.users.find({ _id: { $in: userIdsByOrders } }).forEach(d => print(`${d.firstName}, ${d.lastName}, ${d.profile.email}, ${customers[d.customerId].name},${d.sensitive.active.globalAdmin}, ${(orderTotalsByUserId[d._id.valueOf()] * .01).toFixed(2)}`) )
After some time, I've been able to solve it.
Hope it can be helpful for someone else.
First filtering the featurePermissions field in the pipeline.
Then, created an if statement, indicating that if the user has a Customer, it should print the following values.
The solution was:
var orderTotalsByUserId = {};
db.orders.aggregate([{ $match: { completed: { $exists: true }, completed: { $gt : new Date('2020-08-01') } } }, { $group: { _id: { userId : "$userId" }, total : { $sum: "$total"} } }]).forEach( d => orderTotalsByUserId[d._id.userId] = d.total );
var customers = {};
db.organizations.find().forEach(c => { customers[c._id.valueOf()] = c });
db.users.find({ featurePermissions: { $exists: true } }, { _id: 1, firstName: 1, lastName: 1, profile: 1, customerId: 1, featurePermissions: 1 }).forEach(d => { if (customers[d.customerId]) { print(`${d.firstName}, ${d.lastName}, ${d.profile.email}, ${customers[d.customerId].name}, ${orderTotalsByUserId[d._id.valueOf()] ? (orderTotalsByUserId[d._id.valueOf()] * .01).toFixed(2) : 0 }, ${d.featurePermissions.user_management ? 'true' : 'false' }`)}});

Implement feed with retweets in MongoDB

I want to implement retweet feature in my app. I use Mongoose and have User and Message models, and I store retweets as array of objects of type {userId, createdAt} where createdAt is time when retweet occurred. Message model has it's own createdAt field.
I need to create feed of original and retweeted messages merged together based on createdAt fields. I am stuck with merging, whether to do it in a single query or separate and do the merge in JavaScript. Can I do it all in Mongoose with a single query? If not how to find merge insertion points and index of the last message?
So far I just have fetching of original messages.
My Message model:
const messageSchema = new mongoose.Schema(
{
fileId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'File',
required: true,
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true,
},
likesIds: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
reposts: [
{
reposterId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
},
createdAt: { type: Date, default: Date.now },
},
],
},
{
timestamps: true,
},
);
Edit: Now I have this but pagination is broken. I am trying to use newCreatedAt field for cursor, that doesn't seem to work. It returns empty array in second call when newCreatedAt is passed from the frontend.
messages: async (
parent,
{ cursor, limit = 100, username },
{ models },
) => {
const user = username
? await models.User.findOne({
username,
})
: null;
const options = {
...(cursor && {
newCreatedAt: {
$lt: new Date(fromCursorHash(cursor)),
},
}),
...(username && {
userId: mongoose.Types.ObjectId(user.id),
}),
};
console.log(options);
const aMessages = await models.Message.aggregate([
{
$addFields: {
newReposts: {
$concatArrays: [
[{ createdAt: '$createdAt', original: true }],
'$reposts',
],
},
},
},
{
$unwind: '$newReposts',
},
{
$addFields: {
newCreatedAt: '$newReposts.createdAt',
original: '$newReposts.original',
},
},
{ $match: options },
{
$sort: {
newCreatedAt: -1,
},
},
{
$limit: limit + 1,
},
]);
const messages = aMessages.map(m => {
m.id = m._id.toString();
return m;
});
//console.log(messages);
const hasNextPage = messages.length > limit;
const edges = hasNextPage ? messages.slice(0, -1) : messages;
return {
edges,
pageInfo: {
hasNextPage,
endCursor: toCursorHash(
edges[edges.length - 1].newCreatedAt.toString(),
),
},
};
},
Here are the queries. The working one:
Mongoose: messages.aggregate([{
'$match': {
createdAt: {
'$lt': 2020 - 02 - 02 T19: 48: 54.000 Z
}
}
}, {
'$sort': {
createdAt: -1
}
}, {
'$limit': 3
}], {})
And the non working one:
Mongoose: messages.aggregate([{
'$match': {
newCreatedAt: {
'$lt': 2020 - 02 - 02 T19: 51: 39.000 Z
}
}
}, {
'$addFields': {
newReposts: {
'$concatArrays': [
[{
createdAt: '$createdAt',
original: true
}], '$reposts'
]
}
}
}, {
'$unwind': '$newReposts'
}, {
'$addFields': {
newCreatedAt: '$newReposts.createdAt',
original: '$newReposts.original'
}
}, {
'$sort': {
newCreatedAt: -1
}
}, {
'$limit': 3
}], {})
This can be done in one query, although its a little hack-ish:
db.collection.aggregate([
{
$addFields: {
reposts: {
$concatArrays: [[{createdAt: "$createdAt", original: true}],"$reports"]
}
}
},
{
$unwind: "$reposts"
},
{
$addFields: {
createdAt: "$reposts.createdAt",
original: "$reposts.original"
}
},
{
$sort: {
createdAt: -1
}
}
]);
You can add any other logic you want to the query using the original field, documents with original: true are the original posts while the others are retweets.

Populate Only When Conditions Are Met

I have a mongodb database and I use mongoose with nodejs.
I need return data from the next query populating "tabela_tuss" only if I have the field "temtussvinculado=true".
Here is what I am doing:
ConvProced.find({'convenioId':new ObjectId(req.params.id)})
.populate('convenioId')
.populate({
path:'procedId',
populate:{
path:'tabela_tuss',
match: { 'procedId.temtussvinculado': true}
}
})
.exec( (err,data) => {
callback(err,data,res)
})
My problem is that my match with "procedId.temtussvinculado:true" has no effect and "tabela_tuss" is never populated.
What am I doing wrong?
Here is my schemas:
////
var conveniosSchema = new mongoose.Schema({
nome: {type: String, unique:true},
ativo: {type: Boolean}
});
module.exports = mongoose.model('Convenio', conveniosSchema,'convenios' );
////
////
const agProcedimentosSchema = new mongoose.Schema({
ativo:{type:Boolean},
temtussvinculado:{type:Boolean},
tabela_tuss:{type:mongoose.Schema.Types.ObjectId, ref:'Tuss_22'}
});
module.exports = mongoose.model('Ag_procedimento', agProcedimentosSchema,'ag_procedimentos' );
///
////
const tuss_22Schema = new mongoose.Schema({
codigo: {type: String, unique:true},
descricao:{type: String},
tabela:{type: String}
});
module.exports = mongoose.model('Tuss_22', tuss_22Schema,'tuss_22' );
////
//../models/convenioprocedimento
var conveniosProcedsSchema = new mongoose.Schema({
convenioId:{type:mongoose.Schema.Types.ObjectId, ref:'Convenio'},
procedId:{type:mongoose.Schema.Types.ObjectId, ref:'Ag_procedimento'},
valor_particular:{type:Number},
valor_convenio:{type:Number},
});
module.exports = mongoose.model('ConvenioProcedimento', conveniosProcedsSchema,'conveniosprocedimentos' );
//my query:
const ConvProced = require('../models/convenioprocedimento');
ConvProced.find({'convenioId':new ObjectId(req.params.id)})
.populate('convenioId')
.populate({
path:'procedId',
populate:{
path:'tabela_tuss',
match: { 'procedId.temtussvinculado': true}
}
})
.exec( (err,data) => {
callback(err,data,res)
})
What you are actually asking here is to "Only populate where a condition within the data says to do so", which is something that is not actually a "directly" supported action of .populate() or usage of the "nested populate" syntax.
So if you want to impose "conditions" on which items are actually populated or not, then you must handle the populate calls "manually".
The basic premise in your case is that you would need to inspect the value which you need to get from the "initial" top level .populate() call, but then "only" call the "inner" populate when the given condtions actually allow it.
So your code should then probably look like this using "Promises" using Promise.all() where you basically "loop" or .map() each query result and test the proceedid.temtussvinculado to see if it is true/false, and where true we actually issue a Model.populate() call, otherwise just return the data in it's present state:
ConvProced.find({'convenioId':new ObjectId(req.params.id)})
.populate('convenioId procedId')
.exec()
.then(data =>
Promise.all(
data.map( d =>
( d.proceedid.temtussvinculado )
? mongoose.model('Tuss_22').populate(d,{ path: 'proceedId.tabela_tuss' })
: d
)
)
)
)
// Populated conditionally
.then( data =>
// Do something with data
)
.catch(err => console.error(err)); // or something else with error
There are different options available other than 'Promises', but it is the no dependency option. Alternate cases such as async.map to do much the same thing, but is an additional dependency if you do not already have it:
ConvProced.find({'convenioId':new ObjectId(req.params.id)})
.populate('convenioId procedId')
.exec((err,data) => {
if (err) throw err;
async.map(data,(d,callback) =>
( d.proceedid.temtussvinculado )
? mongoose.model('Tuss_22').populate(d,{ path: 'proceedId.tabela_tuss' },callback)
: callback(null,d)
(err,data) => {
if (err) throw err; // or something
// Conditionally populated
}
)
})
Also demonstrated with a full working example, which is actually a little more complicated than what you need to do, since the "condition" is nested within another array in this example:
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
mongoose.connect('mongodb://localhost/test');
const subInnerSchema = new Schema({
label: String
});
const innerSchema = new Schema({
name: String,
populate: Boolean,
subs: [{ type: Schema.Types.ObjectId, ref: 'Sub' }]
});
const outerSchema = new Schema({
title: String,
inners: [{ type: Schema.Types.ObjectId, ref: 'Inner' }]
});
const Sub = mongoose.model('Sub', subInnerSchema);
const Inner = mongoose.model('Inner', innerSchema);
const Outer = mongoose.model('Outer', outerSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
async.series(
[
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
// Insert some data
(callback) =>
async.waterfall(
[
(callback) =>
Sub.create([1,2,3,4].map( label => ({ label })),callback),
(subs,callback) =>
Inner.create(
[0,2].map(x => subs.slice(x,x+2))
.map((el,i) => ({
name: i+i,
populate: i == 1,
subs: el
})),
callback
),
(inners,callback) =>
Outer.create(
inners.map((inner,i) => ({
title: i+1,
inners: [inner]
})),
callback
),
],
callback
),
// Conditional populate async.map version
(callback) =>
Outer.find().populate('inners').exec((err,outers) => {
if (err) callback(err);
async.map(
outers,
(outer,callback) =>
async.map(
outer.inners,
(inner,callback) =>
(inner.populate)
? Inner.populate(inner,{ path: 'subs' },callback)
: callback(null,inner),
(err,inners) => {
if (err) callback(err);
outer.inners = inners
callback(null,outer);
}
),
(err,outers) => {
if (err) callback(err);
log(outers);
callback();
}
);
}),
// Conditional populate Promise
(callback) =>
Outer.find().populate('inners').exec()
.then(outers =>
Promise.all(
outers.map( outer =>
new Promise((resolve,reject) => {
Promise.all(
outer.inners.map( inner =>
(inner.populate)
? Inner.populate(inner,{ path: 'subs' })
: inner
)
).then(inners => {
outer.inners = inners;
resolve(outer)
})
.catch(reject)
})
)
)
)
.then(outers => {
log(outers);
callback();
})
.catch(err => callback(err))
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
);
Which produces the output showing the "conditional" selection, from using either approach of course:
Mongoose: subs.remove({}, {})
Mongoose: inners.remove({}, {})
Mongoose: outers.remove({}, {})
Mongoose: subs.insert({ label: '1', _id: ObjectId("5961830256bf9e2d0fcf13b3"), __v: 0 })
Mongoose: subs.insert({ label: '2', _id: ObjectId("5961830256bf9e2d0fcf13b4"), __v: 0 })
Mongoose: subs.insert({ label: '3', _id: ObjectId("5961830256bf9e2d0fcf13b5"), __v: 0 })
Mongoose: subs.insert({ label: '4', _id: ObjectId("5961830256bf9e2d0fcf13b6"), __v: 0 })
Mongoose: inners.insert({ name: '0', populate: false, _id: ObjectId("5961830256bf9e2d0fcf13b7"), subs: [ ObjectId("5961830256bf9e2d0fcf13b3"), ObjectId("5961830256bf9e2d0fcf13b4") ], __v: 0 })
Mongoose: inners.insert({ name: '2', populate: true, _id: ObjectId("5961830256bf9e2d0fcf13b8"), subs: [ ObjectId("5961830256bf9e2d0fcf13b5"), ObjectId("5961830256bf9e2d0fcf13b6") ], __v: 0 })
Mongoose: outers.insert({ title: '1', _id: ObjectId("5961830256bf9e2d0fcf13b9"), inners: [ ObjectId("5961830256bf9e2d0fcf13b7") ], __v: 0 })
Mongoose: outers.insert({ title: '2', _id: ObjectId("5961830256bf9e2d0fcf13ba"), inners: [ ObjectId("5961830256bf9e2d0fcf13b8") ], __v: 0 })
Mongoose: outers.find({}, { fields: {} })
Mongoose: inners.find({ _id: { '$in': [ ObjectId("5961830256bf9e2d0fcf13b7"), ObjectId("5961830256bf9e2d0fcf13b8") ] } }, { fields: {} })
Mongoose: subs.find({ _id: { '$in': [ ObjectId("5961830256bf9e2d0fcf13b5"), ObjectId("5961830256bf9e2d0fcf13b6") ] } }, { fields: {} })
[
{
"_id": "5961830256bf9e2d0fcf13b9",
"title": "1",
"__v": 0,
"inners": [
{
"_id": "5961830256bf9e2d0fcf13b7",
"name": "0",
"populate": false,
"__v": 0,
"subs": [
"5961830256bf9e2d0fcf13b3",
"5961830256bf9e2d0fcf13b4"
]
}
]
},
{
"_id": "5961830256bf9e2d0fcf13ba",
"title": "2",
"__v": 0,
"inners": [
{
"_id": "5961830256bf9e2d0fcf13b8",
"name": "2",
"populate": true,
"__v": 0,
"subs": [
{
"_id": "5961830256bf9e2d0fcf13b5",
"label": "3",
"__v": 0
},
{
"_id": "5961830256bf9e2d0fcf13b6",
"label": "4",
"__v": 0
}
]
}
]
}
]
Mongoose: outers.find({}, { fields: {} })
Mongoose: inners.find({ _id: { '$in': [ ObjectId("5961830256bf9e2d0fcf13b7"), ObjectId("5961830256bf9e2d0fcf13b8") ] } }, { fields: {} })
Mongoose: subs.find({ _id: { '$in': [ ObjectId("5961830256bf9e2d0fcf13b5"), ObjectId("5961830256bf9e2d0fcf13b6") ] } }, { fields: {} })
[
{
"_id": "5961830256bf9e2d0fcf13b9",
"title": "1",
"__v": 0,
"inners": [
{
"_id": "5961830256bf9e2d0fcf13b7",
"name": "0",
"populate": false,
"__v": 0,
"subs": [
"5961830256bf9e2d0fcf13b3",
"5961830256bf9e2d0fcf13b4"
]
}
]
},
{
"_id": "5961830256bf9e2d0fcf13ba",
"title": "2",
"__v": 0,
"inners": [
{
"_id": "5961830256bf9e2d0fcf13b8",
"name": "2",
"populate": true,
"__v": 0,
"subs": [
{
"_id": "5961830256bf9e2d0fcf13b5",
"label": "3",
"__v": 0
},
{
"_id": "5961830256bf9e2d0fcf13b6",
"label": "4",
"__v": 0
}
]
}
]
}
]
So you can see there that in much the same way there is a "boolean" field which is being tested to determine whether to perform a .populate() or just return the plain data instead.

mongoose update nested document not working

I try to figure out what I'm doing wrong that moongose is not updating my document. Just for testing the id's are hardcoded.
node.js
var id1 = "592fd471fedd311d5c76a024";
var id2 = "592fd4ad608e001d79938ba8";
Workshop.update({
_id: id1,
'themen._id': id2
}, {
'$set': {
'themen.$.risikolandschaft': ["John", "Doe"],
}
},
function(err, body) {
if (err) {
console.log(err)
} else {
console.log(body);
}
}
);
here my data copied from MongoDB Compass
{
"_id" : ObjectId("592fd471fedd311d5c76a024"),
"clientid" : "592cff8794738f0347609666",
"bezeichnung" : "Workshop 1.5.2017 / 10:46",
"themen" : [
{
"thema" : {
"__v" : 0,
"bezeichnung" : "Sturm",
"beschreibung" : "Text",
"_id" : "59255757b1485d0ad2a6924f"
},
"risikolandschaft" : [ "one", "two", "three"],
"date" : "2017-06-01T08:47:41.944Z",
"_id" : ObjectId("592fd4ad608e001d79938ba8")
}
], ...
the log from body
{ n: 0, nModified: 0, ok: 1 }
for adding a new item to the "themen" subdocument i use this:
var new_thema = {
_id: mongoose.Types.ObjectId(),
date : req.body.date,
risikolandschaft : req.body.risikolandschaft,
thema : req.body.thema };
here the mongoose schema
var WorkshopSchema = mongoose.Schema({
clientid: {
type: String,
required: true
},
bezeichnung: {
type: String,
required: true
},
stammdaten : [],
date : Date,
themen : []
});
and there is no subschema for "themen"
"mongoose": "^4.8.6"

Categories

Resources