I have a collection named 'EloVars' on my mongodb, with only one document:
{
"_id": {
"$oid": "5800f3bfdcba0f48d2c58161"
},
"nextPID": "0",
"TotalComprasions": "0"
}
I'm trying to get the value of nextPID this way:
var myDoc = db.collection('EloVars').find();
if(myDoc) {
console.log('What exactly am I getting here:')
console.log(myDoc)
req.body.pid = myDoc.nextPID;
}
When I look at the console i noticed that what I'm getting is not 'EloVars' collection... just weired long Readable:
Readable {
pool: null,
server: null,
disconnectHandler:
{ s: { storedOps: [], storeOptions: [Object], topology: [Object] },
length: [Getter] },
bson: {},
ns: 'mydb.EloVars',
cmd:
{ find: 'mydb.EloVars',
limit: 0,
skip: 0,
query: {},
slaveOk: true,
readPreference: { preference: 'primary', tags: undefined, options: [Object] } },
options:
.....
.....
What is this readable and why am I getting it?
find() returns a cursor. You have to iterate the cursor to get the documents.
var cursor = db.collection('EloVars').find();
cursor.each(function(err, doc) {
console.log(doc);
});
Or you can convert it to an array to get the documents.
cursor.toArray(function(err, doc){
console.log(doc);
});
Why are you trying in this way? if there is not any specific reason and you just wanted to get "nextPID" the you can use below query:
db.collection('EloVars').findOne({},{_id:0, nextPID:1}).exec(function(err, doc) {
if(doc) {
console.log('What exactly am I getting here:')
console.log(myDoc)
req.body.pid = doc.nextPID;
}
})
P.S.: it'll get only one nextPID.
to get all:
db.collection('EloVars').find({},{_id:0, nextPID:1}).exec(function(err, docs) {
if(docs && docs.length){
// your code here
}
})
Related
findOne()
const solutionList = await CommentMicroserviceDB.collection('comments').findOne({organizationId: ObjectId('5eb393ee95fab7468a79d189')});
Working Fine:-
{
_id: 6364e934830dcc00b488848d,
type: 'DOUBTS',
typeId: 63622eb7ddf697001fdc7b0a,
organizationId: 5eb393ee95fab7468a79d189,
createdBy: 62d53063e34fe92f8a135818,
status: 'Active',
displayOrder: 2,
createdAt: 2022-11-02T09:27:25.000Z,
updatedAt: 2022-11-02T09:27:25.000Z,
text:'<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n<p>Notification beofer berrnern</p>\n</body>\n</html>'
}
find()
const solutionList = await CommentMicroserviceDB.collection('comments').find({organizationId: ObjectId('5eb393ee95fab7468a79d189')});
But when I try with find() function is not working and give me:-
Cursor {
pool: null,
server: null,
disconnectHandler: Store { s: [Object], length: [Getter] },
bson: BSON {},
ns: 'comment_service.comments',
cmd:
{ find: 'comment_service.comments',
limit: 0,
skip: 0,
slaveOk: true },
options:
{ readPreference: [ReadPreference],
skip: 0,
limit: 0,
topology: [Server] },
.....
.....
sortValue: undefined }
Why this is happening ?
findOne function is working perfectly but find not
i need find here because i need all docs with given organizationId
Can anyone tell me
Thanks!!!
db.collection.find() returns a Cursor which is A pointer to the result set of a query. Clients can iterate through a cursor to retrieve results.
Refer to official collection.find() documentation.
If you just want the array of documents, try appending .toArray() at the end of your find query.
Try this:
const solutionList = await CommentMicroserviceDB.collection('comments').find({
organizationId: ObjectId('5eb393ee95fab7468a79d189')
}).toArray();
Read more about .toArray() here
I am trying to update one document using findOneAndUpdate and $set but I clearly missing something very crucial here because the new request is overwriting old values.
My Device schema looks like this:
{
deviceId: {
type: String,
immutable: true,
required: true,
},
version: {
type: String,
required: true,
},
deviceStatus: {
sensors: [
{
sensorId: {
type: String,
enum: ['value1', 'value2', 'value3'],
},
status: { type: Number, min: -1, max: 2 },
},
],
},
}
And I am trying to update the document using this piece of code:
const deviceId = req.params.deviceId;
Device.findOneAndUpdate(
{ deviceId },
{ $set: req.body },
{},
(err, docs) => {
if (err) {
res.send(err);
} else {
res.send({ success: true });
}
}
);
And when I try to send a request from the postman with the body that contains one or multiple sensors, only the last request is saved in the database.
{
"deviceStatus": {
"sensors": [
{
"sensorId": "test",
"status": 1
}
]
}
}
I would like to be able to update values that are already in the database based on req.body or add new ones if needed. Any help will be appreciated.
The documentation said:
The $set operator replaces the value of a field with the specified
value.
You need the $push operator, it appends a specified value to an array.
Having this documents:
[
{
_id: 1,
"array": [
2,
4,
6
]
},
{
_id: 2,
"array": [
1,
3,
5
]
}
]
Using $set operator:
db.collection.update({
_id: 1
},
{
$set: {
array: 10
}
})
Result:
{
"_id": 1,
"array": 10
}
Using $push operator:
db.collection.update({
_id: 1
},
{
$push: {
array: 10
}
})
Result:
{
"_id": 1,
"array": [
2,
4,
6,
10
]
}
you want to using $push and $set in one findOneAndUpdate, that's impossible, I prefer use findById() and process and save() ,so just try
let result = await Device.findById(deviceId )
//implementation business logic on result
await result.save()
If you want to push new sensors every time you make request then update your code as shown below:
const deviceId = req.params.deviceId;
Device.findOneAndUpdate(
{ deviceId },
{
$push: {
"deviceStatus.sensors": { $each: req.body.sensors }
}
},
{},
(err, docs) => {
if (err) {
res.send(err);
} else {
res.send({ success: true });
}
}
);
Update to the old answer:
If you want to update sensors every time you make request then update your code as shown below:
const deviceId = req.params.deviceId;
Device.findOneAndUpdate(
{ "deviceId": deviceId },
{ "deviceStatus": req.body.sensors },
{ upsert: true },
(err, docs) => {
if (err) {
res.send(err);
} else {
res.send({ success: true });
}
}
);
I'm working on an app using MongoDB and Express.js.
I am creating a post handler that updates a toy (found by its id) with a new proposed name for the toy (which is pushed onto a nameIds array that contains the ids of the other proposed names):
router.post('/names', (req, res) => {
const toyId = req.body.toyId;
const name = req.body.newName;
mdb.collection('names').insertOne({ name }).then(result =>
mdb.collection('toys').findAndModify({
query: { id: toyId },
update: { $push: { nameIds: result.insertedId } },
new: true
}).then(doc =>
res.send({
updatedToy: doc.value,
newName: { id: result.insertedId, name }
})
)
)
});
However, when I test this, I receive this error:
name: 'MongoError',
message: 'Either an update or remove=true must be specified',
ok: 0,
errmsg: 'Either an update or remove=true must be specified',
code: 9,
codeName: 'FailedToParse'
I'm not new to MongoDB, but this simple call is baffling me.
Thanks for any help you can provide!
That is the format for mongo shell. Using mongo driver you would call with these arguments:
.findAndModify( //query, sort, doc, options, callback
{ id: toyId }, //query
[], //sort
{ $push: { nameIds: result.insertedId } }, // doc update
{ new: true }, // options
function(err,result){ //callback
if (err) {
throw err
} else {
res.send({
updatedToy: result.value,
newName: { id: result.insertedId, name }
})
}
}
)
I think I know how to get to my object, I just can't figure out how to update it's values. I am getting this error:
{
"name": "MongoError",
"message": "cannot use the part (tasks of families.25.tasks.name) to traverse the element ({tasks: [ { name: \"Correct Name\", isSelected: false, completedBy: null, submittedBy: \"web-user\", completedOn: null, submittedOn: new Date(1505857352113), message: \"Please correct family name to follow HOK standard.\", assignedTo: \"konrad.sobon\", _id: ObjectId('59c18f8991d1929d43f22f8c') }, { name: \"Some other task\", isSelected: false, completedBy: null, submittedBy: \"web-user\", completedOn: null, submittedOn: new Date(1505917405948), message: \"Yet again, testing this.\", assignedTo: \"konrad.sobon\", _id: ObjectId('59c279fb8388cb58e7454bf6') } ]})",
"driver": true,
"index": 0,
"code": 16837,
"errmsg": "cannot use the part (tasks of families.25.tasks.name) to traverse the element ({tasks: [ { name: \"Correct Name\", isSelected: false, completedBy: null, submittedBy: \"web-user\", completedOn: null, submittedOn: new Date(1505857352113), message: \"Please correct family name to follow HOK standard.\", assignedTo: \"konrad.sobon\", _id: ObjectId('59c18f8991d1929d43f22f8c') }, { name: \"Some other task\", isSelected: false, completedBy: null, submittedBy: \"web-user\", completedOn: null, submittedOn: new Date(1505917405948), message: \"Yet again, testing this.\", assignedTo: \"konrad.sobon\", _id: ObjectId('59c279fb8388cb58e7454bf6') } ]})"
}
My collection looks like this:
My request handler looks like this:
module.exports.updateTask = function (req, res) {
var id = req.params.id;
var taskId = mongoose.Types.ObjectId(req.params.taskid);
Families
.update(
{ _id: id, 'families.tasks._id': taskId},
{ $set: {
'families.$.tasks.name': req.body.name,
'families.$.tasks.message': req.body.message,
'families.$.tasks.assignedTo': req.body.assignedTo}}, function(err, result){
if(err) {
res
.status(400)
.json(err);
} else {
res
.status(202)
.json(result);
}
}
)
};
Any help will be appreciated.
Unfortunately the positional operator $ cannot be used for nested arrays:
The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value.
https://docs.mongodb.com/manual/reference/operator/update/positional/
You might have to consider restructuring your documents.
I have this query that works, but I want for the doc to only display network.stations.$ instead of the entire array. If I write fields: network.stations.$, I get an error. Is there a way for the doc only to return a single element from [stations]?
Network.findOneAndUpdate({
"network.stations.id": req.params.station_Id
}, {
"network.stations.$.free_bikes": req.body.free_bikes
}, {
new: true,
fields: "network.stations"
}, (err, doc) => console.log(doc))
// I want doc to somehow point only to a single station instead of
// several stations like it currently does.
The answer is "yes", but not in the way you are expecting. As you note in the question, putting network.stations.$ in the "fields" option to positionally return the "modified" document throws a specific error:
"cannot use a positional projection and return the new document"
This however should be the "hint", because you don't really "need" the "new document" when you know what the value was you are modifying. The simple case then is to not return the "new" document, but instead return it's "found state" which was "before the atomic modification" and simply make the same modification to the returned data as you asked to apply in the statement.
As a small contained demo:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const testSchema = new Schema({},{ strict: false });
const Test = mongoose.model('Test', testSchema, 'collection');
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
await Test.remove();
await Test.insertMany([{ a: [{ b: 1 }, { b: 2 }] }]);
for ( let i of [1,2] ) {
let result = await Test.findOneAndUpdate(
{ "a.b": { "$gte": 2 } },
{ "$inc": { "a.$.b": 1 } },
{ "fields": { "a.$": 1 } }
).lean();
console.log('returned');
log(result);
result.a[0].b = result.a[0].b + 1;
console.log('modified');
log(result);
}
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})();
Which produces:
Mongoose: collection.remove({}, {})
Mongoose: collection.insertMany([ { __v: 0, a: [ { b: 1 }, { b: 2 } ], _id: 59af214b6fb3533d274928c9 } ])
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } })
returned
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 2
}
]
}
modified
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 3
}
]
}
Mongoose: collection.findAndModify({ 'a.b': { '$gte': 2 } }, [], { '$inc': { 'a.$.b': 1 } }, { new: false, upsert: false, fields: { 'a.$': 1 } })
returned
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 3
}
]
}
modified
{
"_id": "59af214b6fb3533d274928c9",
"a": [
{
"b": 4
}
]
}
So I'm doing the modifications in a loop so you can see that the update is actually applied on the server as the next iteration increments the already incremented value.
Merely by omitting the "new" option, what you get is the document in the state which it was "matched" and it then is perfectly valid to return that document state before modification. The modification still happens.
All you need to do here is in turn make the same modification in code. Adding .lean() makes this simple, and again it's perfectly valid since you "know what you asked the server to do".
This is better than a separate query because "separately" the document can be modified by a different update in between your modification and the query to return just a projected matched field.
And it's better than returning "all" the elements and filtering later, because the potential could be a "very large array" when all you really want is the "matched element". Which of course this actually does.
Try changing fields to projection and then use the network.stations.$ like you tried before.
If your query is otherwise working then that might be enough. If it's still not working you can try changing the second argument to explicitly $set.
Network.findOneAndUpdate({
"network.stations.id": req.params.station_Id
}, {
"$set": {
"network.stations.$.free_bikes": req.body.free_bikes
}
}, {
new: true,
projection: "network.stations.$"
}, (err, doc) => console.log(doc))