Monday, July 23, 2018

A cursor based custom pagination library for Mongoose with customizable labels.

Installation

npm install mongoose-paginate-v2

Usage

Add plugin to a schema and then use model paginate method:
var mongoose         = require('mongoose');
var mongoosePaginate = require('mongoose-paginate-v2');

var mySchema = new mongoose.Schema({ 
    /* your schema definition */ 
});

mySchema.plugin(mongoosePaginate);

var myModel = mongoose.model('SampleModel',  mySchema); 

myModel.paginate().then({}) // Usage

Model.paginate([query], [options], [callback])

Returns promise
Parameters
  • [query] {Object} - Query criteria. Documentation
  • [options] {Object}
    • [select] {Object | String} - Fields to return (by default returns all fields). Documentation
    • [sort] {Object | String} - Sort order. Documentation
    • [populate] {Array | Object | String} - Paths which should be populated with other documents. Documentation
    • [lean=false] {Boolean} - Should return plain javascript objects instead of Mongoose documents? Documentation
    • [leanWithId=true] {Boolean} - If lean and leanWithId are true, adds id field with string representation of _idto every document
    • [offset=0] {Number} - Use offset or page to set skip position
    • [page=1] {Number}
    • [limit=10] {Number}
    • [customLabels] {Object} - Developers can provide custom labels for manipulating the response data.
  • [callback(err, result)] - If specified the callback is called once pagination results are retrieved or when an error has occurred
Return value
Promise fulfilled with object having properties:
  • docs {Array} - Array of documents
  • totalDocs {Number} - Total number of documents in collection that match a query
  • limit {Number} - Limit that was used
  • hasPrevPage {Bool} - Availability of prev page.
  • hasNextPage {Bool} - Availability of next page.
  • page {Number} - Current page number
  • totalPages {Number} - Total number of pages.
  • offset {Number} - Only if specified or default page/offset values were used
  • prevPage {Number} - Previous page number if available or NULL
  • nextPage {Number} - Next page number if available or NULL
Please note that the above properties can be renamed by setting customLabel attribute.

Sample Usage

Return first 10 documents from 100

const options = {
    page: 1,
    limit: 10
};

Model.paginate({}, options, function(err, result) {
    // result.docs
    // result.totalDocs = 100
    // result.limit = 10
    // result.page = 1
    // result.totalPages = 10    
    // result.hasNextPage = true
    // result.nextPage = 2
    // result.hasPrevPage = false
    // result.prevPage = null
    
});

With custom return labels

Now developers can specify the return field names if they want. Below are the list of attributes whose name can be changed.
  • totalDocs
  • docs
  • limit
  • page
  • nextPage
  • prevPage
  • totalPages
You should pass the names of the properties you wish to changes using customLabels object in options.
Same query with custom labels
const myCustomLabels = {
    totalDocs: 'itemCount',
    docs: 'itemsList',
    limit: 'perPage',
    page: 'currentPage',
    nextPage: 'next',
    prevPage: 'prev',
    totalPages: 'pageCount'
};

const options = {
    page: 1,
    limit: 10,
    customLabels: myCustomLabels
};

Model.paginate({}, options, function(err, result) {
    // result.itemsList [here docs become itemsList]
    // result.itemCount = 100 [here totalDocs becomes itemCount]
    // result.perPage = 10 [here limit becomes perPage]
    // result.currentPage = 1 [here page becomes currentPage]
    // result.pageCount = 10 [here totalPages becomes pageCount]
    // result.next = 2 [here nextPage becomes next]
    // result.prev = null [here prevPage becomes prev]
    
    // result.hasNextPage = true [not changeable]
    // result.hasPrevPage = false [not changeable]
});

Other Examples

Using offset and limit:
Model.paginate({}, { offset: 30, limit: 10 }, function(err, result) {
    // result.docs
    // result.totalPages
    // result.limit - 10
    // result.offset - 30
});
With promise:
Model.paginate({}, { offset: 30, limit: 10 }).then(function(result) {
    // ...
});

More advanced example

var query   = {};
var options = {
    select:   'title date author',
    sort:     { date: -1 },
    populate: 'author',
    lean:     true,
    offset:   20, 
    limit:    10
};

Book.paginate(query, options).then(function(result) {
    // ...
});

Zero limit

You can use limit=0 to get only metadata:
Model.paginate({}, { offset: 100, limit: 0 }).then(function(result) {
    // result.docs - empty array
    // result.totalDocs
    // result.limit - 0
    // result.offset - 100
});

Set custom default options for all queries

config.js:
var mongoosePaginate = require('mongoose-paginate-v2');

mongoosePaginate.paginate.options = { 
    lean:  true,
    limit: 20
};
controller.js:
Model.paginate().then(function(result) {
    // result.docs - array of plain javascript objects
    // result.limit - 20
});

Tuesday, July 17, 2018

How to add title and image header to all pages while printing using DataTable

Step 1

Download below JS file and replace your print.button.js with below it,https://github.com/aravindnc/Buttons/blob/repeating-print-head/js/buttons.print.js

Step 2

Add new option repeatingHead inside the button settings.
Below are the options for repeatingHead,
{
    logo: 'Your logo URL to be repeated',
    logoPosition: 'right', // left, center, right
    logoStyle: '', // any css eg: padding:10px;
    title: '

Sample Heading

'
// your heading }
A sample is given below.
<script>
    $(document).ready(function() {
        // DataTable initialisation
        $('#example').DataTable({
            "dom": 'Bfrtip',
            "paging": true,
            "autoWidth": true,
            "columnDefs": [{
                "visible": true,
                "targets": -1
            }],
            buttons: [{
                extend: 'print',
                autoPrint: true,
                title: '',

                //For repeating heading.
                repeatingHead: {
                    logo: 'https://www.google.co.in/logos/doodles/2018/world-cup-2018-day-22-5384495837478912-s.png',
                    logoPosition: 'right',
                    logoStyle: '',
                    title: '

Sample Heading

'
} }] }); }); </script>

Step 3

If you want to remove the borders around logo, add a new class dt-print-table to your table and add below style to your css file.
@media print
{
html, body { height: auto; }
.dt-print-table, .dt-print-table thead, .dt-print-table th, .dt-print-table tr {border: 0 none !important;}
}
Thats all :)

Tuesday, January 16, 2018

Create signed AWS request using PHP

Here is a simple way to generate a signed request for diferent services using AWS:


/// AWS API keys
$aws_access_key_id = 'your-aws-access-key';
$aws_secret_access_key = 'your-aws-secret';

// AWS region and Host Name (Host names are different for each AWS region)
// As an example these are set to us-west-2
$aws_region = 'us-west-2';
$host_name = 'your-url.amazonaws.com';

// MIME type of file.
$content_type = 'application/x-www-form-urlencoded';

// Service name
$aws_service_name = 'execute-api';

// UTC timestamp and date
$timestamp = gmdate('Ymd\THis\Z');
$date = gmdate('Ymd');

// HTTP request headers as key & value
$request_headers = array();
$request_headers['content-type'] = $content_type;
$request_headers['x-amz-date'] = $timestamp;
$request_headers['host'] = $host_name;

// Sort it in ascending order
ksort($request_headers);

// Canonical headers
$canonical_headers = [];
foreach($request_headers as $key => $value) {
$canonical_headers[] = strtolower($key) . ":" . $value;
}
$canonical_headers = implode("\n", $canonical_headers);

// Signed headers
$signed_headers = [];
foreach($request_headers as $key => $value) {
$signed_headers[] = strtolower($key);
}
$signed_headers = implode(";", $signed_headers);


// Cannonical request 
$canonical_request = [];
$canonical_request[] = "GET";
$canonical_request[] = "/getStatus";
$canonical_request[] = "order_id=123456";
$canonical_request[] = $canonical_headers;

//This is needed do not remove
$canonical_request[] = "";

$canonical_request[] = $signed_headers;

//If there are no content then put blank.
$canonical_request[] = hash('sha256', '');

$canonical_request = implode("\n", $canonical_request);
$hashed_canonical_request = hash('sha256', $canonical_request);

// AWS Scope
$scope = [];
$scope[] = $date;
$scope[] = $aws_region;
$scope[] = $aws_service_name;
$scope[] = "aws4_request";

// String to sign
$string_to_sign = [];
$string_to_sign[] = "AWS4-HMAC-SHA256"; 
$string_to_sign[] = $timestamp; 
$string_to_sign[] = implode('/', $scope);
$string_to_sign[] = $hashed_canonical_request;
$string_to_sign = implode("\n", $string_to_sign);

// Signing key
$kSecret = 'AWS4' . $aws_secret_access_key;
$kDate = hash_hmac('sha256', $date, $kSecret, true);
$kRegion = hash_hmac('sha256', $aws_region, $kDate, true);
$kService = hash_hmac('sha256', $aws_service_name, $kRegion, true);
$kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);

// Signature
$signature = hash_hmac('sha256', $string_to_sign, $kSigning);

// Authorization
$authorization = [
' Credential=' . $aws_access_key_id . '/' . implode('/', $scope),
' SignedHeaders=' . $signed_headers,
' Signature=' . $signature
];
$authorization = 'AWS4-HMAC-SHA256' . ' ' . implode( ',', $authorization);

// Curl headers
$curl_headers = [ 'authorization: ' . $authorization ];
foreach($request_headers as $key => $value) {
$curl_headers[] = $key . ": " . $value;
}

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://your-url.amazonaws.com/getStatus?order_id=123456",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_SSL_VERIFYHOST => false,
  CURLOPT_SSL_VERIFYPEER => false,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "GET",
  CURLOPT_HTTPHEADER => $curl_headers
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

Popular Posts