Mongodb find and insert - mongodb

I would like to:
1) find documents
2) each of the found documents include an array, I would like to insert a new array element into the array. If the array element already exists, do nothing (do not insert a new element into the array).
I've played with aggregation however I can't seem to find an insert function?
Data:
{
"_id" : ObjectId("560c24b853b558856ef193a4"),
"name" : "ирина",
"pic" : "",
"language" : ObjectId("560c24b853b558856ef193a2"),
"cell" : 1,
"local" : {
"email" : "ирина#mail.com",
"password" : "12345"
},
"sessions" : [ // <--- this is the array I would like to insert a new element into
{
"id" : ObjectId("560c24b853b558856ef193a5")
}
]
}
Insert:
yield new Promise(function (resolve, reject) {
users.col.aggregate([
{
$match: {
'cell': socket.cell
}
},
{
// <--- insert here?
}
],
function (err, res) {
if (err === null)
resolve(res);
reject(err);
});
});
Update.
Tried the following also not willing to insert :/
yield new Promise(function (resolve, reject) {
var bulk = users.col.initializeUnorderedBulkOp();
bulk.find({
cell: 1
}).update({
$addToSet: {
sessions: {
id: 'test'
}
}
});
bulk.execute(function (err, res) {
console.log(res);
resolve(res);
});
});

As stated by user3100115 you should use update as follows:
db.collection.update({cell:1},{$addToSet:{sessions:{id: 'test'}}},{multi:true})

Using co-monk:
yield users.update({
cell: 1
}, {
$addToSet: {
sessions: {
id: 'test'
}
}
}, {
multi: true
});

You can use Bulk operations, particularly Bulk.find and update. As for adding unique values, you can use $addToSet
var bulk = db.items.initializeUnorderedBulkOp();
bulk.find({cell: socket.cell}).update({$addToSet: {sessions: id}});

Related

How to return a specific field in mongodb?

Here is my code, it searches the word 'test' through all documents in 'subs' collection and return them.
The thing is I just need two specific fields (id and name).
app.get('/', (req, res) => {
db.collection('subs')
.find({
$text: { $search: 'test' },
})
.toArray((err, result) => {
if (err) {
throw new err();
}
res.json({
length: result.length,
body: { result },
});
});
});
So you can use a projection:
db.collection('subs').find({$text: { $search: 'test' }}, {name: 1 } ).
Read more about it here: https://docs.mongodb.com/manual/tutorial/project-fields-from-query-results/#return-the-specified-fields-and-the-_id-field-only
you can set the fields you need in additional argument to the find method :
db.collection('subs').find({
$text: { $search: 'test' }
},
{
name: 1,
otherColumn: 1
}); // select only the "name" & the "otherColumn" column
The _id column is always returned by default, but you could disable it by adding _id: 0.
Hope this solve your question.
Finally I found the answer! :
.find(
{
name: { $in: ['Prison Break', 'Dexter'] },
$text: { $search: 'kill' },
},
{
projection: { name: 1 },
}
)

Mongoose update only fields available in request body

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 });
}
}
);

MongoDB putting they key into $set instead of using it for lookup?

I am trying to update a message using userID as my _id
Is splitting it up into findOne - Save - Update the best way?
//
// Find and update message
//
var messageModel = require('../models/messageModel');
var messageTable = mongoose.model('messageModel');
var messageRecord = new messageModel();
var findMessage = () => {
return new Promise((resolve, reject) => {
console.log("=====START findMessage=====")
messageTable.findOne(
{ _id: userID }
,function(err, data) {
if (err) {
reject(new Error('findMessage: ' + err))
return;
}
// Who will have this as unread?
if (userManager==true) {
messageRecord.readUser = false;
messageRecord.readManager = true;
} else {
messageRecord.readUser = true;
messageRecord.readManager = false;
}
// If message not found, then create new one
if (!data) {
console.log("=====CREATE NEW RECORD=====")
messageRecord._id = userID;
messageRecord.activityDate = Math.round(new Date().getTime()/1000);
messageRecord.messages = {
"message" : message,
"date" : Math.round(new Date().getTime()/1000),
"property" : propertyID,
"booking" : bookingID,
"manager" : userManager
}
messageRecord.save(function (err, res) {
if (err) {
reject(new Error('findMessage: ' + err));
return;
}
})
console.log("=====RESOLVE findMessage=====")
resolve();
return;
}
// If message found, then add message
console.log("=====ADD LINE TO RECORD=====")
messageTable.update (
{ _id: userID },
{
$set: {
activityDate : Math.round(new Date().getTime()/1000),
readUser : messageRecord.readUser,
readManager : messageRecord.readManager
},
$push: {
messages: {
"message" : message,
"date" : Math.round(new Date().getTime()/1000),
"property" : propertyID,
"booking" : bookingID,
"manager" : userManager
}
}
},
{ upsert: true }
).exec(function (err, res) {
if (err) {
reject(new Error('findMessage: ' + err));
return;
}
})
console.log("=====RESOLVE findMessage=====")
resolve();
return;
});
})};
Do I need to put upsert:true? (what ever that means)
Or should I use findOneAndUpdate?
And would you use findOneAndUpdate or just update? And why?
I tought it went like this:
findone
if not found then save
if found then update
UPDATE - Thanks to lascot I ended up doing this, and it works great!
// Save message
messageTable.update (
{ _id: userID },
{
$setOnInsert: {
_id: userID
},
$set: {
activityDate : Math.round(new Date().getTime()/1000),
readUser : messageRecord.readUser,
readManager : messageRecord.readManager
},
$push: {
messages: {
"message" : message,
"date" : Math.round(new Date().getTime()/1000),
"property" : propertyID,
"booking" : bookingID,
"manager" : userManager
}
}
},
{ upsert: true }
).exec(function (err, res) {
if (err) {
reject(new Error('findMessage: ' + err));
return;
}
})

update if exist insert if it doesn't exist for sub docs in mongoose

I see every relevant links for my data there is not a proper solution.
My Schema is like this:
{
"_id" : ObjectId("590aa0e68d4b23760d8d0e50"),
"updatedAt" : ISODate("2017-05-08T07:03:08.314Z"),
"createdAt" : ISODate("1987-12-31T16:00:00.000Z"),
"Avatar" : "public/image/test.pic",
"countries" : [
{
"code" : "MY",
"is_favourite" : false,
"is_visited" : true,
},
{
"code" : "CA",
"is_favourite" : true
}
]
}
I want to add a country like this:
{
"code" : "QC",
"is_favourite" : true
}
if it does exist just update it from false to true or vise versa, otherwise insert the new object.
I write code for it but it seems long story and also it is not working correctly in insert mode(get this error : The positional operator did not find the match needed from the query). I would be grateful for any helps ....
var query = {"_id":req.params._id, "countries":{$elemMatch:{code:req.body.code}}}
var update = { $set: {"countries.$.is_favourite": req.body.is_favourite}}
var option = {"upsert": true}
User.findOneAndUpdate(query,update,option, function (err, user) {
if (err) return next(err);
return res.status(201).json({
success: true,
message: 'country '+ '<'+req.body.code+'> '+ 'updated as '
+req.body.is_favourite
});
});
This is what i have tested and works perfectly as expected.
Logic is pretty clear you just need to make small changes.
updateTestTable: function (req, res, callback) {
var pushData = {
"code": "QC",
"is_favourite": true
};
console.log("INSIDE");
var objectID=new mongoose.Types.ObjectId("59119107fd4790422fcb676a");
test.findOne({"_id":objectID,"countries.code":pushData.code},function(err,data){
console.log(JSON.stringify(data));
if(data!==null){
//Update Data
console.log("HELLO");
test.findOneAndUpdate({"_id":objectID,"countries.code":pushData.code},{ $set: { "countries.$.is_favourite": false} },function(err,data){
if(data){
console.log("DATA UPDATED");
console.log(data);
}
else{
console.log("ERR",err);
}
});
}
else{
//Insert Data
test.findOneAndUpdate({"_id":objectID},{$push: {countries: pushData }},function(err,data){
if(data){
console.log("DATA INSERTED");
console.log(data);
}
});
}
});
},

How to use aggregrate in mongodb to $match _id

Document:
{
"_id" : ObjectId("560c24b853b558856ef193a3"),
"name" : "Karl Morrison",
"pic" : "",
"language" : ObjectId("560c24b853b558856ef193a2"),
"cell" : 1,
"local" : {
"email" : "karl.morrison#instanty.se",
"password" : "12345"
},
"sessions" : [
{
"id" : ObjectId("560c24b853b558856ef193a5")
}
]
}
This works:
yield new Promise(function (resolve, reject) {
users.col.aggregate([
{
$match: {
'name': 'Karl Morrison'
}
}
],
function (err, res) {
console.log('err ' + err);
console.log('res ' + JSON.stringify(res)); // <-- echos the object retrieved
if (err === null)
resolve(res);
reject(err);
});
});
This does not work:
yield new Promise(function (resolve, reject) {
users.col.aggregate([
{
$match: {
'_id': '560c24b853b558856ef193a3' // <-- _id of the user
}
}
],
function (err, res) {
console.log('err ' + err);
console.log('res ' + JSON.stringify(res));
if (err === null)
resolve(res);
reject(err);
});
});
The .col access the native mongodb object (using co-monk otherwise). So I'm doing it manually. This however isn't working. I suspect I am not casting the id hexstring to an ObjectId. No matter what I try nothing works.
const ObjectId = mongoose.Types.ObjectId;
const User = mongoose.model('User')
User.aggregate([
{
$match: { _id: ObjectId('560c24b853b558856ef193a3') }
}
])
Try this
const User = require('User')
const mongoose = require("mongoose");
User.aggregate([
{
$match: { _id: new mongoose.Types.ObjectId('560c24b853b558856ef193a3') }
}
])
use toString() method
const User = mongoose.model('User')
User.aggregate([
{
$match: { _id: user_id.toString() }
}
]