I having problems using couchbase map functions with boolean key.
I wrote a map function with a boolean parameter, but when I try to use this function passing the value "false" as key the function returns nothing
Sample Document:
{
"name": "lorem ipsum",
"presentationId": "presentation_24e53b3a-db43-4d98-8499-3e8f3628a9c6",
"fullPrice": 8,
"isSold": false,
"buyerId": null,
"type": "ticket",
}
Map Function:
function(doc, meta) {
if (doc.type == "ticket" && doc.isSold && doc.presentationId) {
emit([doc.isSold, doc.presentationId], null);
}
}
http://localhost:8092/default/_design/tickets/_view/by_presentation_and_isSold?key=[false,"presentation_24e53b3a-db43-4d98-8499-3e8f3628a9c6"]
Result:
{"total_rows":10,"rows":[]}]}
You are having this problem due to the check you do for the doc.isSold before the emit statement, the check means that only documents where doc.isSold == TRUE are passing through.
What you need to do is this which will check that the variable has been set rather than evaluating the boolean value:
function(doc, meta) {
if (doc.type == "ticket" && doc.isSold != null && doc.presentationId) {
emit([doc.isSold, doc.presentationId], null);
}
}
Hope that helps :)
Related
How can I write a test for an empty value of a specific JSON name pair. For example I have this JSON:
{
"data": {
"sectionGroupName": "PPConfig:APIMethod",
"sections": {}
},
"success": true,
"errorMessage": ""
}
I want to check if sections is empty, like it is in this case. I have other successful tests written like this:
tests["Status code is 200"] = responseCode.code === 200;
var body = JSON.parse(responseBody);
tests["Success Response"] = body.success === true;
tests["No Error message"] = body.errorMessage === "";
tests.Data = body.data.sectionGroupName === "PPConfig:APIMethod";
But I haven't been able to find successful test code for checking if the value of a specific name is an empty dictionary. Can someone help me with this as an example please?
You can get the list of properties of sections and test its length.
let sectionKeys = Object.keys(body.data.sectionGroupName)
if(sectionKeys.length){
//Proceed with section
} else {
//Proceed when it's empty
}
See Object.keys()
from this link
to check if it's a dictionary (use your 'sections' as v)
function isDict(v) {
return !!v && typeof v==='object' && v!==null && !(v instanceof Array) && !(v instanceof Date) && isJsonable(v);
}
Then check that it is empty (from this other link) use:
function isEmpty(obj) {
for (var x in obj) { return false; }
return true;
}
That should work
UPDATE
As developer003 suggested, I did this:
It works, but not at all. If I add an other property as c.details.author (string[]) or c.details.index (number), it doesn't work, and the function doesn't return nothing (error).
Here an extract of my JSON database:
[
{
"index": 1,
"name": "ad dolor ipsum quis",
"details": {
"author": ["Wallace Stephens", "Steve Ballmer"],
"game": {
"short": "tdp",
"name": "Thief: The Dark Project"
},
"newdark": {
"required": true,
"version": "1.20"
},
"firstreleasedate": "2007/04/27",
"lastupdatedate": "2017/01/28"
}
}
]
So I can look for another details properties than strings. Any idea?
ORIGINAL POST
I created a function which, when I call it as a (keyup) event, filters an HTML datatable when I type something in an input.
return c.name.toLowerCase().indexOf(input.target.value.toLowerCase()) != -1;
I want to be able to filter, not only by name, but also by details.author, details.game.name, details.firstrelease... etc.
How can I change c.name to apply these properties? Do I need to create a loop? Should I use .map()?
Right now I can think in 2 approaches:
1st:
º Create a function to parse (toLowerCase()) the property value and handle if it contains the value or not:
containsVal(property, value) {
return property.toLowerCase().indexOf(value) !== -1;
}
filterFunc(c) {
return this.containsVal(c.name, VALUE_TO_SEARCH) ||
c.details && (
this.containsVal(c.details.author, VALUE_TO_SEARCH) ||
this.containsVal(c.details.firstrelease, VALUE_TO_SEARCH) ||
(c.details.game && this.containsVal(c.details.game.name, VALUE_TO_SEARCH))
);
}
2nd:
º Map the only needed properties and filter them.
arr.map(item => {
return {
name: item.name,
author_details: item.details && item.details.author,
firstrelease_details: item.details && item.details.firstrelease,
game_name: item.details && item.details.game && item.details.game.name
};
}).filter(item => {
return Object.keys(item).some(key => {
const value = item[key];
return value && value.toLowerCase().indexOf(VALUE_TO_SEARCH) !== -1;
});
});
I'm trying to convert any item within a JSON object to a string. JSON.stringify won't work because it doesn't convert the individual values. If its an object or number, I want the entire object to be a string. How do I test if typeof is NOT a string. I can't figure out why this doesn't work...
if (typeof(value) !== 'string') {
return String(value);
}
Any insights? Full example below:
var myjson = {
"current_state":"OPEN",
"details":"Apdex < .80 for at least 10 min",
"severity":"WARN",
"incident_api_url":"https://alerts.newrelic.com/api/explore/applications/incidents/1234",
"incident_url":"https://alerts.newrelic.com/accounts/99999999999/incidents/1234",
"owner":"user name",
"policy_url":"https://alerts.newrelic.com/accounts/99999999999/policies/456",
"runbook_url":"https://localhost/runbook",
"policy_name":"APM Apdex policy",
"condition_id":987654,
"condition_name":"My APM Apdex condition name",
"event_type":"INCIDENT",
"incident_id":1234
};
function replacer(key, value) {
if (typeof(value) !== 'string') {
return String(value);
}
return value;
}
console.log(JSON.stringify(myjson, replacer));
This actually isn't a problem with the typeof comparison.
The replacer function is initially called with an empty key and a value representing the entire JSON object (reference). Since the JSON object is not a string, the first thing your replacer function does is replace the whole JSON object with the string "[object Object]".
To fix this, check that the key does, in fact exist. Thus, your replacer function will look like this:
function replacer(key, value) {
if (key && (typeof(value) !== 'string')) {
return String(value);
}
return value;
}
I have a working fiddle of it here as well.
Angular.js has a handy built-in filter, json, which displays JavaScript objects as nicely formatted JSON.
However, it seems to filter out object properties that begin with $ by default:
Template:
<pre>{{ {'name':'value', 'special':'yes', '$reallyspecial':'Er...'} | json }}</pre>
Displayed:
{
"name": "value",
"special": "yes"
}
http://plnkr.co/edit/oem4HJ9utZMYGVbPkT6N?p=preview
Can I make properties beginning with $ be displayed like other properties?
Basically you can't. It is "hard-coded" into the filter's behaviour.
Nonetheless, it is quite easy to build a custom JSON filter that behaves identically with the Angular's one but not filtering out properties starting with '$'.
(Scroll further down for sample code and a short demo.)
If you take a look at the 1.2.15 version source code, you will find out that the json filter is defined like this:
function jsonFilter() {
return function(object) {
return toJson(object, true);
};
}
So, it uses the toJson() function (the second parameter (true) means: format my JSON nicely).
So, our next stop is the toJson() function, that looks like this:
function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined;
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
This function makes use of the "native" JSON.stringify() function, passing a custom replacer function (toJsonReplacer).
The toJsonReplacer() function handles some special cases: It checks if the key starts with $ and ignores it if it does (this is what we want to change) and it checks if the value is either a Window, a Document or a Scope object (in which case it converts it to a descriptive string in order to avoid "Converting circular structure to JSON" errors).
function toJsonReplacer(key, value) {
var val = value;
if (typeof key === 'string' && key.charAt(0) === '$') {
val = undefined;
} else if (isWindow(value)) {
val = '$WINDOW';
} else if (value && document === value) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
return val;
}
For the sake of completeness, the two functions that check for Window and Scope look like this:
function isWindow(obj) {
return obj && obj.document && obj.location && obj.alert && obj.setInterval;
}
function isScope(obj) {
return obj && obj.$evalAsync && obj.$watch;
}
Finally, all we need to do is to create a custom filter that uses the exact same code, with the sole difference that our toJsonReplacer() won't filter out properties starting with $.
app.filter('customJson', function () {
function isWindow(obj) {
return obj &&
obj.document &&
obj.location &&
obj.alert &&
obj.setInterval;
}
function isScope(obj) {
return obj &&
obj.$evalAsync &&
obj.$watch;
}
function toJsonReplacer(key, value) {
var val = value;
if (isWindow(value)) {
val = '$WINDOW';
} else if (value && (document === value)) {
val = '$DOCUMENT';
} else if (isScope(value)) {
val = '$SCOPE';
}
return val;
}
function toJson(obj, pretty) {
if (typeof obj === 'undefined') { return undefined; }
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
}
return function(object) {
return toJson(object, true);
};
});
See, also, this short demo.
* The downside is that your custom JSON filter will not benefit from further improvement/enhancement of Angular's json filter, so you'll have to re-define your's to incorporate changes. Of course, for such a basic and simple filter like this, one should'nt expect frequent or extensive changes, but that doesn't mean there aren't going to be any.
When using:
var dataToSave = ko.toJSON(myViewModel);
.. is it possible to not serialize values that are null?
Serializing my current viewModel creates around 500Kb of JSON most of which is ends up like:
"SomeObject": {
"Property1": 12345,
"Property2": "Sometext",
"Property3": null,
"Property4": null,
"Property5": null,
"Property6": null,
"Property7": null,
"Property8": null,
"Property9": false
}
If I could get the serializer to ignore null values then this could be reduced down to:
"SomeObject": {
"Property1": 12345,
"Property2": "Sometext",
"Property9": false
}
Any ideas how I can instruct the serializer to ignore the null values??
Remember that ko.toJSON is just a modification of JSON stringify. You can pass in a replacer function.
As an example of using a replacer function in Knockout, I put together a JSFiddle based on one of the knockout tutorials. Notice the difference between the makeJson and makeCleanJson functions. We can choose not to return any values in our replacer function and the item will be skipped in the JSON string.
self.makeJson = function() {
self.JsonInfo(ko.toJSON(self.availableMeals));
};
self.makeCleanJson = function() {
self.JsonInfo(ko.toJSON(self.availableMeals, function(key, value) {
if (value == null)
{
return;
}
else
{
return value;
}
}));
};
You can add a toJSON method to your view model and use that to remove all the unneeded properties:
ViewModel.prototype.toJSON = function() {
var copy = ko.toJS(this);
// remove any unneeded properties
if (copy.unneedProperty == null) {
delete copy.unneedProperty;
}
return copy;
}
You could probably automate it to run through all your properties and delete the null ones.