How to upsert MongoCollection but keep some values? - javascript

Hi,
I don't know how to put a good title for it but I'm sure you will understand
So I'm trying to set 2 fields on my Mongo collection when the user click on a button BUT every 60sc I have a method that is running and who make that:
upsertCollectionMachines = Meteor.bindEnvironment(function() {
machinesCount = 0;
var protocol;
var port;
Machine.list({
inspect: true
}, Meteor.bindEnvironment(function(err, machines) {
if (typeof machines === "undefined") {
console.error("Impossible to access 'machines' from 'Machine.list: '" + err);
} else {
machines.forEach(Meteor.bindEnvironment(function(machineInfo) {
machinesCount += 1;
if (machineInfo.url != null) {
var urlToArray = machineInfo.url.split(":")
port = urlToArray[urlToArray.length - 1];
protocol = "https";
} else {
port = "2376";
protocol = "https";
}
InfosMachines.upsert({
nameMachine: machineInfo.name,
}, {
nameMachine: machineInfo.name,
stateMachine: machineInfo.state,
ipAddr: machineInfo.driver.ipAddress,
port: port,
protocol: protocol
//here I want to add isUsed: false,
//whoUseIt: "", but I think if I set isUsed true --> after 60s it will be false again right ?
});
}));
if (apiKeyGenerated == false) {
getTheAPIKeyGrafana(function(err, res) {
if (!err) {
apiKeyGenerated = true;
updateDashboard();
} else {
console.error(err);
}
});
}else{
updateDashboard();
}
}
}));
})
Where the important part is the InfosMachines.upsert(). Now I want to set 2 fields like this :
'lockTheMachine': function(nameMachine, nameUser){
InfosMachines.upsert({
nameMachine: nameMachine,
}, {
nameMachine: nameMachine,
isUsed: true,
whoUseIt: nameUser
});
//upsertCollectionMachines();
console.log(nameUser +" has locked the machine: " + nameMachine);
},
But first it doesn't look likes it add the 2fields to the collection and secondly the 60s interval method will delete them right ?
Thank you for the help

It was a little hard to follow exactly what you are trying to do in your question, but I think I got the main gist of it.
Basically, you want the lockTheMachine() function upsert to only ever set nameMachine, isUsed, and whoUseIt fields and you only want upsertCollectionMachines() to set stateMachine, ipAddr, port, protocol fields on update and only set isUsed and whoUseIt to default values on insert?
You should be able to do that using the below upserts.
Use this upsert inside your upsertCollectionMachines() function.
InfosMachines.upsert({
nameMachine: machineInfo.name,
}, {
$set: {
stateMachine: machineInfo.state,
ipAddr: machineInfo.driver.ipAddress,
port: port,
protocol: protocol
},
$setOnInsert: {
isUsed: false,
whoUseIt: "",
}
});
It will always set stateMachine, ipAddr, port, protocol fields regardless if it is inserting or updated, but will only modify isUsed and whoUseIt if it is inserting (therefore, it will not overwrite the values set from the other function).
Use this upsert inside your lockTheMachine() function.
InfosMachines.upsert({
nameMachine: nameMachine,
}, {
$set: {
isUsed: true,
whoUseIt: nameUser
}
});
It will only ever insert or update those 2 specific fields (isUsed and whoUseIt).
Now, why does this work? First, we are using update operator expressions (instead of only field:value expressions) which allow you to only update specific fields when needed and using $setOnInsert ensures that we only ever modify those fields on insert only. Note, that if the upsert determines it needs to insert a new document, per the mongodb upsert option behavior, it creates a new document using...
The fields and values of both the <query> and <update> parameters if the <update> parameter contains update operator expressions
This means you don't have to ever actually $set the nameMachine field explicitly in the update expression.

Related

Get Invite_link by getUpdates method Telegram-API

I want to know the link which was used by the user to join the group and I try to get the invite_link derived from this variable :
But, when I used getUpdates() method to receive incoming updates (Update is the object on which ChatMemberUpdated is),it didn't include invite_link.
This is the code (nodejs):
await client.getUpdates({ offset : 0, allowed_updates : 'chat_member' }).then(async function(update) {
console.log(update)
if (update.length != 0){
fs.appendFile('update.txt', JSON.stringify(update), function (err) {
if (err) throw err
console.log('Saved!')
})
}
})
And this is the result:
[{"update_id":xx96xxxxx,"message":{"message_id":2xxxx,"from":{"id":x669xxxxxx,"is_bot":false,"first_name":"xx.nwxxx","language_code":"es"},"chat":{"id":-xxxx4506xxxxx,"title":"xxxxxxx","type":"supergroup"},"date":xxx195xxxx,"new_chat_participant":{"id":xxx9660xxx,"is_bot":false,"first_name":"xxxnwxxx","language_code":"es"},"new_chat_member":{"id":xxx9660xxx,"is_bot":false,"first_name":"xxxnwxxx","language_code":"es"},"new_chat_members":[{"id":xxx9660xxx,"is_bot":false,"first_name":"xxxnwxxx","language_code":"es"}]}}]
At the moment to create the invite_link, you need to specified "creates_join_request" as true. Otherwise, the bot cannot detect the link.

How to add group or role based restriction to some action in YouTrack workflow?

I have created a workflow to restrict the changes in the estimation once it has been added. However, I want to give this permission to the Admins but restrict all other groups such as Developers.
I have tried isInGroup function but it's not working correctly and I always get an exception.
var entities = require('#jetbrains/youtrack-scripting-api/entities');
var workflow = require('#jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: 'Protect_estimations',
guard: function(ctx) {
if(!ctx.current.isInGroup('Admin')) {
return (ctx.issue.fields.oldValue(ctx.Estimation) !== null && ctx.issue.fields.isChanged(ctx.Estimation) === true); }
return false; },
action: function(ctx) {
workflow.check(false,'Sorry, you cannot update estimates'); },
requirements: {
Estimation: {
type: entities.Field.periodType,
name: 'Estimation'
} } });
The condition !ctx.current.isInGroup('Admin') does not work whereas rest of the code is running perfect. Do I need to add any rule in the 'requirements' section in order to get this done? Please suggest.
To resolve the issue, I suggest you use the currentUser property instead:
if(!ctx.currentUser.isInGroup('Admin'))...
I hope this helps.

node.js code does not read else condition when user does not specify a search argument (only reads if condition)

Currently, my if/else statement does not work correctly as it never goes to the else portion of my code. The node app takes in an argument (process.argv[3]) and uses that to pick the API to call. process.argv[4] is used to specify what to search (example "Yesterday") and works correctly if argument is provided. However, I want to have a default search if user leaves that argument blank. I'm unsure of why it never goes to the else portion of the code.
I'm new to programming so I'm sure this is stupid error on my part, but I've tried rewritting the statement and same issue. Any help would be greatly appreciated.
function getSpotifySongInfo() {
//4th node argument is reserved for the song user wants to select
var query = process.argv[3];
if (query !== "") {
//could make this less repeating code by passing the song as a parameter?
spotifyClient.search({ type: 'track', query: query, limit: 1 }, function (err, data) {
if (!err) {
console.log("=============Artist==Track==Album==PreviewURL=============================");
console.log("Artist: " + data.tracks.items[0].artists[0].name);
console.log("Track: " + data.tracks.items[0].name);
console.log("Album: " + data.tracks.items[0].name);
console.log("Preview URL: " + data.tracks.items[0].preview_url);
} else {
console.log(err);
}
});
} else {
//need to make this specific for Ace of Base. For some reason it's not changing the query to reflect default song. I've tried commenting this portion out and just testing w/ a simple console.log("test") and nothing...
query = 'The Sign';
spotifyClient.search({ type: 'track', query: query, limit: 1 }, function (err, data) {
if (!err) {
console.log("=============Artist==Track==Album==PreviewURL=============================");
console.log("Artist: " + data.tracks.items[0].artists[0].name);
console.log("Track: " + data.tracks.items[0].name);
console.log("Album: " + data.tracks.items[0].name);
console.log("Preview URL: " + data.tracks.items[0].preview_url);
} else {
console.log(err);
}
});
}
}
if (query !== "") is a bad test and probably doesn't do what you want. For example:
var query = undefined;
query !== ""
// true
query = null
query !== ""
// true
You are testing for a very specific thing — an empty string — which you probably aren't getting as an argument to your function.
A better way that leads to a lot less code is to assign a value to query if none exists. You can do some thing like:
if (!query) {
query = 'The Sign'
}
Then you don't need the if/else code at all. A quick and easy way to do this is:
var query = process.argv[3] || 'The Sign'
This will either assign the value of process.argv[3] or, if that value is falsy, you'll get the default. This is a very common pattern in Javascript.

indexeddb put not update a value, it creates a new (id)

I have a table with form, surname, lastname, email and a rectangle. I have to insert, in the rectangle, an array with arrays with points of timelines etc. I create a customer with form, surname, lastname and email, add them to indexeddb, load them later to insert the rectangle-array. After that, I want to put the newobjectstore in the indexeddb where the email is the same from my customer I choose/inserted. But with this code my array will be put in a new Objectstore with its own ID.
function cmd_SaveRec(hypeDocument, elementID)
{
hypeDocument.getElementById('rectext').innerHTML = hypeDocument.getElementById('beschriftung').value;
var store_cust = db.transaction(["customer"], "readwrite").objectStore("customer").index("rectangle");
var cursorReq = store_cust.openCursor();
cursorReq.onsuccess = function (e) {
cursor = e.target.result;
if(cursor) {
if(cursor.value.email == mailAdd)
{
//cursor.update([rec_ar]);
if(store_cust.objectStore.put({rectangle: [rec_ar]}))
{
console.info(store_cust.objectStore);
console.info('Gespeichert');
alert("Gespeichert");
} else {
console.info('cmd_SaveRec::Problem');
}
}
cursor.continue();
}
};
cursorReq.onerror = function(e) {
console.log("Error");
console.dir(e);
}
}
var store_cust = evt.currentTarget.result.createObjectStore(
DB_STORE_NAME_CUSTOMER, { keyPath: 'cust_id', autoIncrement: true });
store_cust.createIndex('form', 'form', { unique: false }); //
store_cust.createIndex('surname', 'surname', { unique: false });
store_cust.createIndex('lastname', 'lastname', { unique: false });
store_cust.createIndex('email', 'email', { unique: true });
store_cust.createIndex('rectangle', 'rectangle', { unique: false, multiEntry: true });
Short answer
Provide an identifier/key as a second parameter in objectStor.put(data, key) or
Use a IDBCursor und update it as stated here in the docs
Explanation
As described in the docs:
The put() method of the IDBObjectStore interface updates a given record in a database, or inserts a new record if the given item does not already exist. (source developer.mozilla.org)
Your used method objectStore.put() is for insert or update tasks. If I get you right you're looking for an update - cursor.update() is your friend here (you commented out). - This is the preferred method here !
But you could do it with both methods. Say you would like to update but if the record not exists create one. In such a case the engine have to know if your record exists and what record do you try to update.
If your objectStore uses an autoIncrementing primary key the identifier of the record is not in the record itself so you have to provide the id as a second parameter to your put() function.
I find it easier to take care of the ids by myself. Then the id is part of the record (findable under the keypath you provided at objectStore-creation). Then your code could work as expected... certainly you have to add a key:value pair for an id.
Examples
// create a store with ids YOU handle e.g.
var request = indexedDB.open(dbname, dbversion+1);
request.onerror = errorHandler;
request.onupgradeneeded = function(event){
var nextDB = request.result;
if (!nextDB.objectStoreNames.contains('account')) {
nextDB.createObjectStore('account', {keyPath: "id", autoIncrement: true});
}
}
// Your record has to llok like this
{id: 123456789, rectangle: [rec_ar]}
// Now your code above should work
If you have a primary key in your db:
store_cust.objectStore.put({rectangle: [rec_ar]}, PRIMARY_KEY)
// where PRIMARY_KEY is the id of this specific record
By the way
Don't use if-else to check the completness of the transaction - it is asynchronus - if/else lies everytime here - use callbacks as I stated in my example above (onsuccess).
You should read the docs from my cite. Mozilla is a great ressource for indexedDB stuff.

Proper way to findOne document in Template Event?

I am trying to findOne document in my Template.admin.events code. I have a form and onClick I want to verify if the ID of the ObjectID entered is an existing document in my collection and fetch that result to show it on the template.
My event code on the client :
Template.admin.events({
'click #btnAjouterObjet'(event) {
let objetIdInput = $('#object_id').val().toString();
Meteor.subscribe('objetsFindOne', objetIdInput, {
onReady: function () {
let obj = Objets.findOne();
if (obj) {
console.log("found");
console.log(obj);
objetsArr.push(objetIdInput);
}
else {
console.log("not found");
console.log(obj);
}
}
});
}
});
In my Objets api :
Meteor.publish('objetsFindOne', function objetsFindOne(param_id){
return Objets.find({_id : param_id});
})
I have verified and my objetIdInput always change on click when a different Id is entered but the subscribe always returns the first id entered. I also added the onReady because otherwise it returned undefined.
I am new to Meteor and I have also tried to subscribe to all the collection and doing the find on the client but I don't think it is the best idea as my collection has about 22000 documents.
Just to elaborate a little bit on the first answer, as to how to change this pattern:
(1) you should place your Meteor.subscribe() call in your Template.admin.onCreated() function.
(2) the subscription reads from a reactive value, for example, new ReactiveVar().
(3) now, anytime the reactive value changes, the subscription will re-run. So, in your template event, you set the reactive value to the id and let the subscription handle the rest.
Discover Meteor and other resources should be helpful on any details.
You are going about this all wrong. I suggest you take a look at Template-Level Subscriptions
I opted for the use of a method :
Client side:
'click #btnAjouterObjet'(event) {
let objetIdInput = $('#object_id').val().toString();
let result = Meteor.call('findObj', objetIdInput, function (error, result) {
if (error) {
console.log(error.reason);
return;
}
console.log(result);
});
}
On the server side :
Meteor.methods({
findObj: function (param_id) {
console.log(Objets.find({ _id: param_id }).fetch());
return Objets.find({ _id: param_id }).fetch();
},
});

Categories

Resources