How to validate $set 'keys' with MongoDB? - javascript

I've got a rather specific case: Using mongoose/mongo and user objects
I want to find and update user in one call.
DB.collection('users').findOneAndUpdate({localId: id} ,{ "$set": { "name": "lla", "usnme": "As"} } ,callback);
Note that 'username' is spelled wrong. Yet mongo updated the first field(name) and does not give any error about the second.
How can I validate the keys I pass in $set without making more than one query?

What MongoDB suggests here is called schema validation:
In your specific case you could run the following command to make sure that no additional ("incorrect") fields can be added by anyone:
db.runCommand({ "collMod": "users", "validator": {
$jsonSchema: {
additionalProperties: false,
properties: {
"_id": {
bsonType: "objectId"
},
"name": {
bsonType: "string"
},
"username": {
bsonType: "string"
}
}
}
}})
Beyond that I cannot really think of any solution since MongoDB is a document database which by default is schemaless and hence won't stop you from creating the fields you tell it to create...

Related

Firestore document update using REST api

I'm trying to increment one value in firebase store using rest api following this guide https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/commit
I'm trying to make the request using the form given at this documentation.
Here's my path to the document
/hindiscript-likes/kof97lbQ1IuuvgCHBfOh
where hindiscript-likes is the collection name.
The document looks like below
Here's my request body
{
"writes": [
{
"transform": {
"document": "projects/public-api-07/databases/(default)/documents/kof97lbQ1IuuvgCHBfOh",
"fieldTransforms": [
{
"increment": {
"integerValue": 1
}
}
]
}
}
]
}
But upon executing this, it is returnng 400 with the following error
{
"error": {
"code": 400,
"message": "Document name \"projects/public-api-07/databases/(default)/documents/kof97lbQ1IuuvgCHBfOh\" lacks \"/\" at index 73.",
"status": "INVALID_ARGUMENT"
}
}
Can somebody help ?
You're missing the name of the collection in the path of the document to update. What you have now is asking for just "kof97lbQ1IuuvgCHBfOh", which it assumes is the name of a collection but a missing document ID. But what you want instead is "hindiscript-likes/kof97lbQ1IuuvgCHBfOh".
Try:
"document": "projects/public-api-07/databases/(default)/documents/hindiscript-likes/kof97lbQ1IuuvgCHBfOh",

Rest API Patch only 1 field at a time

I'm working on an inline grid editor that calls an express rest api after a single value in the grid is updated. So when a user changes a single field in the grid, I am calling a PATCH request to update the field. However I can't figure out how to only update a single field. When I try it tries to update them all and if there's no value it makes the value NULL in the database. I want to only update a single field, and only the one passed into the API (it could be any of the fields). Here's my method to patch:
// Update record based on TxnID
router.patch('/editablerecords/update', function (req, res) {
let qb_TxnID = req.body.txnid
let type = req.body.type;
let margin = req.body.margin;
if (!qb_TxnID) {
return res.status(400).send({ error:true, message: 'Please provide TxnID' });
}
connection.query("UPDATE pxeQuoteToClose SET ? WHERE qb_TxnID = '" + qb_TxnID + "'", { type, margin }, function (error, results, fields) {
if(error){
res.send(JSON.stringify({"status": 500, "error": error, "response": null }));
//If there is error, we send the error in the error section with 500 status
} else {
res.send(JSON.stringify({ error: false, data: results, message: 'Record updated.' }));
//If there is no error, all is good and response is 200OK.
}
});
});
I will only be updating 1 field at a time, either type or margin, but not both (in this case) at the same time. If I only send one of the fields, the other field becomes null. I've tried to read up on the connection.query() method but can find no information and I don't understand how it builds the query, except that every req.body.value that is passed to it gets used to build the query.
I'm new to building this REST API and feel like I'm missing something simple.
EDIT: I'd like to add, I MAY want to update both fields, but I'd also like to update a single field at a time. Thanks
Per the RFC, the body of a PATCH call should not be the updated representation, but rather a set of instructions to apply to the resource.
The PATCH method requests that a set of changes described in the
request entity be applied to the resource identified by the Request-
URI. The set of changes is represented in a format called a "patch
document" identified by a media type.
One good proposed standard for using PATCH with JSON can be found at https://www.rfc-editor.org/rfc/rfc6902. An example patch document using that standard would be:
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]

Error getting a single value from a collection

I have a collection called notification and i am trying to get a single value with findOne()
var allnotices = Notifications.findOne({eventownernumber:"2"},{sort: {noticedate: -1, limit: 1}}).noticemessage;
I want to get the value where the eventownernumber is 2 and i want to get the latest record and i only want one record.
Even though noticemessage is part of the row fields,i get the error that noticemessage is undefined.
This is the schema
{
"_id": "tmkWCydSKZtYdrKTZ",
"eventoriginalid": "3bXvARk6K6yhee6Hi",
"lat": "-1.851881824302658",
"lng": "96.987469482421875",
"eventownernumber": "1",
"eventownernames": "Test 1",
"eventtitle": "ci",
"eventtime": "08:05",
"invited": "0",
"eventduration": "21",
"eventtype": "notification",
"eventcategory": "hackathon",
"eventstatus": "11",
"createdAt": {
"$date": "2016-11-02T12:38:40.378Z"
},
"noticedate": {
"$date": "2016-11-02T16:50:53.394Z"
},
"noticenumber": "2",
"noticenames": "Test 2",
"noticemessage": "Test 2 has joined your event ci",
"noticestatus": "12"
}
Why is noticemessage undefined?.
There are four basic possibilities why Collection.findOne(query).key could yield an error:
There is no document matching the query therefore you're trying to reference undefined.key
The key in question doesn't exist in the returned document
The document exists in the database but isn't being published by the server and being subscribed to by the client
The document exists and is published and subscribed to but the subscription is not yet .ready(), i.e. you need to wait before you can access it.
A common defensive pattern is:
const oneDoc = myCollection.findOne(query);
let myVar = oneDoc && oneDoc.key;
if ( myVar ) {
// do the thing
} else {
// handle the error
}
You need to save the number as integer for eventownernnumber (and please write it like eventOwnerNumber, which is a good practice for readability), not string. Either use input type="number" or convert the value to integer like this:
Number(valueHere);
The rest of your query looks fine to me but you don't need limit since you do findOne() and you find the newest inserted doc with noticedate: -1
Another thing is, you need to save the date like this in your insert():
noticeDate: new Date() //your current query should give you the right document after this change

Firebase basics - JavaScript and forms validation

I want to use Firebase to create coupon codes database. My data structure is following:
[
{
"couponCode": "string",
"isAvailable": true
},
{
"couponCode": "string",
"isAvailable": true
},
...
]
I wont to get couponCode key value and next check value for isAvailable key. If couponCode is valid I want to change value for isAvailable key to false. How to create this validation using Firebase API?
If couponCodes are unique, you're probably better off storing the data like this:
"couponCodes": {
"couponCode1": {
"available": true
},
"couponCode2": {
"available": true
}
}
Now if a user is trying to claim a coupon, you run a transaction on that code:
ref.child('couponCodes').child('couponCode1').transaction(function(current) {
if (current && current.available) {
current.available = false;
// TODO: this is the moment that you'll also want to give the user the discount for the coupon
}
return current;
});

Set a value with mongoose in NodeJS

I have a NodeJS application that communicates with an Angular app. This is a simplified version, but I'll try to explain my problem:
I will get a value from the socket connection, for example:
{
Id : "1",
Checked : true,
TeamName : "Team1"
}
I want to update the mongoDb with mongoose so that every person with the TeamName : "Team1" gets the value Checked : true.
I have done something like this:
relayModel.find({TeamName : 'Team1'},
{'$set' :{Checked: true}},function(err,docs){
if(err){
console.log("Could not save value for relay runner: ", err);
}
else{
console.log("The runners updated: ",docs)
}
But I get the error:
Could not save value for relay runner:
{ [MongoError: Can't canonicalize query:
BadValue Unsupported projection option:
$set: { Checked: true }] name: 'MongoError' }
This really is well documented. Will go away for sure, but just to explain for you:
relayModel.update(
{ "TeamName": "Team1" },
{ "$set": { "Checked": true } },
{ "multi": true },
function(err,numAffected) {
if (err) throw err;
console.log( "updated n docs: %s", numAffected );
}
);
So the .update() with a "multi" option affects more than one document, and without it it just affects the first document matched. The returned values in the callback are the standard err and the "number of documents affected".
Therefore basically speaking:
You actually need and operator that "updates" in order to affect and update.
You set "multi" for more than one document and you get only the number returned as well as using the $set operator to just affect the field that you want to change.

Categories

Resources