Pouchdb map reduce query not returning document - mapreduce

I'm pulling my hair out because of a simple PouchDB map reduce query problem. I would really appreciate it if you can identify the problem in my code.
The problem: the query below does not return any documents in the result, even though I passed in {include_doc: true} and "total_rows" returned is 3.
========== code begin ================================
import moment from 'moment';
import PouchDB from 'pouchdb';
import MemoryAdapter from 'pouchdb-adapter-memory';
PouchDB.plugin(MemoryAdapter);
var db = new PouchDB("test", { adapter: 'memory' });
async function testMapReduce(){
var ddoc = {
_id: '_design/testmsg_index',
views: {
by_year: {
//doc.createdAt - ISO format: "2019-03-02T09:53:44.232Z"
map: function(doc){
if (doc.type == 'testmsg'){
var ymd = doc.createdAt.split('T')[0].split('-');
var year = ymd[0];
emit(year);
}
}.toString()
}
}
}
await db.put(ddoc);
await db.post({type: "testmsg", from: "user1",
createdAt: moment("2011-01-01 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
await db.post({type: "testmsg", from: "user2",
createdAt: moment("2012-02-04 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
await db.post({type: "testmsg", from: "user3",
createdAt: moment("2013-03-02 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
await db.post({type: "testmsg", from: "user4",
createdAt: moment("2014-04-04 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
await db.post({type: "testmsg", from: "user5",
createdAt: moment("2015-05-08 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
await db.post({type: "testmsg", from: "user6",
createdAt: moment("2016-06-11 8:23am", "YYYY-MM-DD HH:mma").toISOString()});
var docs = await db.query('testmsg_index/by_year', {
startkey: 2012,
endkey:2015,
limit: 10,
include_docs : true
});
console.log("query result=", docs);
}
testMapReduce();
================= code end ==========================
query result= {total_rows: 3, offset: 0, rows: Array(0)}

I found the problem myself. The problem was caused by a wrong data type emitted in the design document. A correct design document looks like this:
var ddoc = {
_id: '_design/testmsg_index',
views: {
by_year: {
//doc.createdAt - ISO format: "2019-03-02T09:53:44.232Z"
map: function(doc){
if (doc.type == 'testmsg'){
var ymd = doc.createdAt.split('T')[0].split('-');
var year = parseInt(ymd[0]);
emit(year);
}
}.toString()
}
}
}

Related

Description field is coming as [ARRAY] instead of the actual array([1,2,3]) in dynamodb when I try to get data using query

Items: [
{
Continent: 'Continent#Antarctica',
SKCountry: 'Country#Chile',
CreatedAt: 1668579154424,
description: [Array],
PKContinent: 'PKContinent',
id: 16,
UpdatedAt: 1668579154424
},
{
Continent: 'Continent#Antarctica',
SKCountry: 'Country#France',
CreatedAt: 1668579154424,
description: [Array],
PKContinent: 'PKContinent',
id: 15,
UpdatedAt: 1668579154424
}]
, this is what I am getting but instead of "description: [Array],", I want this, description: [value1, value2, value3]. Also, I am getting this data in console but in browser I am getting an error in console (Uncaught TypeError: Cannot read properties of undefined (reading 'tagName')).
this is the code snippet in getAllItems.
var AWS = require("aws-sdk");
AWS.config.update({
region: "local",
endpoint: "http://localhost:8000"
});
var docClient = new AWS.DynamoDB.DocumentClient()
var table = "Tourism";
const getAllItems = async ()=> {
var PKContinent = "PKContinent";
//console.log("check",PKContinent)
const params = {
TableName: table,
KeyConditionExpression: "PKContinent = :pkUpdate AND begins_with(SKCountry, :SKCountry)",
ExpressionAttributeValues: {
":pkUpdate": PKContinent,
":SKCountry": "Country#"
}
}
docClient.query(params, function (error, data) {
if (error) {
console.log(error)
} else {
var viewArray = [];
if (data.Items.length === 0) {
console.log("data doesn't exists.")
}
else {
console.log(data);
}
}
})
}
module.exports = {
docClient,
getAllItems
};
this is the code in getAll
var express = require('express');
var router = express.Router();
const { getAllItems} = require('../getAllItems');
router.get('/', async (req, res, next) => {
try {
const getData = await getAllItems();
res.json(getData);
} catch (err) {
console.error(err);
res.status(500).json({ err: 'Something went wrong with get' });
}
});
module.exports = router;
For me I believe the issue is when saving the data, not reading it.
You mention you cannot read the data in tbe console? Can you share a screenshot of how that looks in your question.
And can you also share the output of the console which you stated worked, I'll be able to guide you to the issue then.

API request getting stuck in POSTMAN?

So, I am making an e-shop app which uses Mongo DB and Express JS as the backend. I have already created the productSchema, userSchema and the categorySchema and have coded for the appropriate GET requests.
I have made a jwt.js file which handles whether the the GET request should be allowed or not based on the token.
The code for jwt.js is given below
const { expressjwt } = require("express-jwt");
function authJwt() {
const secret = process.env.secret;
const api = process.env.API_URL;
return expressjwt({
secret,
algorithms: ["HS256"],
isRevoked: isRevoked,
}).unless({
path: [
{ url: /\/api\/v1\/products(.*)/, methods: ["GET", "OPTIONS"] },
{ url: /\/api\/v1\/categories(.*)/, methods: ["GET", "OPTIONS"] },
`${api}/users/login`,
`${api}/users/register`,
],
});
}
async function isRevoked(req, payload, done) {
if (!payload.isAdmin) {
done(null, true);
}
done();
}
module.exports = authJwt;
The code for products.js which handles the GET, POST, PUT and DELETE requests for the products database is given below.
const { Product } = require("../models/product");
const express = require("express");
const { Category } = require("../models/category");
const router = express.Router();
const mongoose = require("mongoose");
router.get(`/`, async (req, res) => {
// localhost:3000/api/v1/products?categories=2342342,234234
let filter = {};
if (req.query.categories) {
filter = { category: req.query.categories.split(",") };
}
const productList = await Product.find(filter).populate("category");
if (!productList) {
res.status(500).json({ success: false });
}
res.send(productList);
});
router.get(`/:id`, async (req, res) => {
const product = await Product.findById(req.params.id).populate("category");
if (!product) {
res.status(500).json({ success: false });
}
res.send(product);
});
router.post(`/`, async (req, res) => {
const category = await Category.findById(req.body.category);
if (!category) return res.status(400).send("Invalid Category");
let product = new Product({
name: req.body.name,
description: req.body.description,
richDescription: req.body.richDescription,
image: req.body.image,
brand: req.body.brand,
price: req.body.price,
category: req.body.category,
countInStock: req.body.countInStock,
rating: req.body.rating,
numReviews: req.body.numReviews,
isFeatured: req.body.isFeatured,
});
product = await product.save();
if (!product) return res.status(500).send("The product cannot be created");
res.send(product);
});
router.put("/:id", async (req, res) => {
if (!mongoose.isValidObjectId(req.params.id)) {
return res.status(400).send("Invalid Product Id");
}
const category = await Category.findById(req.body.category);
if (!category) return res.status(400).send("Invalid Category");
const product = await Product.findByIdAndUpdate(
req.params.id,
{
name: req.body.name,
description: req.body.description,
richDescription: req.body.richDescription,
image: req.body.image,
brand: req.body.brand,
price: req.body.price,
category: req.body.category,
countInStock: req.body.countInStock,
rating: req.body.rating,
numReviews: req.body.numReviews,
isFeatured: req.body.isFeatured,
},
{ new: true }
);
if (!product) return res.status(500).send("the product cannot be updated!");
res.send(product);
});
router.delete("/:id", (req, res) => {
Product.findByIdAndRemove(req.params.id)
.then((product) => {
if (product) {
return res
.status(200)
.json({ success: true, message: "the product is deleted!" });
} else {
return res
.status(404)
.json({ success: false, message: "product not found!" });
}
})
.catch((err) => {
return res.status(500).json({ success: false, error: err });
});
});
router.get(`/get/count`, async (req, res) => {
const productCount = await Product.countDocuments((count) => count);
if (!productCount) {
res.status(500).json({ success: false });
}
res.send({
productCount: productCount,
});
});
router.get(`/get/featured/:count`, async (req, res) => {
const count = req.params.count ? req.params.count : 0;
const products = await Product.find({ isFeatured: true }).limit(+count);
if (!products) {
res.status(500).json({ success: false });
}
res.send(products);
});
module.exports = router;
Now, the codes for the users.js and categories.js are similar and thus I am not sharing it.
I am getting the problem when doing GET request for products using POSTMAN API. Even though I am passing the correct token using BEARER TOKEN field in the POSTMAN API, it is getting stuck at sending request. When I delete the isRevoked part, everything works fine, but then again I can't control the get request based on the isAdmin part. So, the problem is in the isRevoked part. But, what exactly is the issue. It seems fine to me logically.
the problem could arise from so many things, could not say without a deeper look at your code but, here are some suggestions:
should isRevoked be async?
does your payload contains isAdmin?
and if so, inside the if statement should be done(null, false) after the if statement you should get a userid or any sort of unique fields such as userEmail, ..., then use your userModel to query the user document so that your last done() be done(null, user)

What is the correct syntax for saving a GeoPoint in Baqend?

What is the correct syntax for saving latitude and longitude in Baqend?
I am successfully saving the normal fields (all of them are strings):
handleSubmit(event) {
event.preventDefault();
var newcompany = new db.Companies({
name: this.state.name,
photo: '',
geo: '47.626814;-122.357345',
address1: this.state.address1,
address2: this.state.address2,
city: this.state.city,
state: this.state.state,
zip: this.state.zip,
});
newcompany.insert().then(() => {
//console.log(newcompany)
this.setState({
redirect: true,
newcompanykey: newcompany.key
})
})
}
But I can't seem to get the geo to save correctly. Probably because I'm treating it as a string and that is not correct?
In the example code I'm just hardcoding it now to values I know are good so we can get this working.
I think the answer here is that the sdk provides a function that encodes it correctly:
handleSubmit(event) {
event.preventDefault();
var geo = new db.GeoPoint(47.626814, -122.357345)
var newcompany = new db.Companies({
name: this.state.name,
photo: '',
geo: geo,
address1: this.state.address1,
address2: this.state.address2,
city: this.state.city,
state: this.state.state,
zip: this.state.zip,
});
newcompany.insert().then(() => {
//console.log(newcompany)
this.setState({
redirect: true,
newcompanykey: newcompany.key
})
})
}

Apollo client recursive mutations

Is the following example possible with apollo-client?
For an example an easy ToDo application and bad internet connection:
no internet connection
(1. mutation) create a new todo
(1. mutation => optimistic update) show the new todo (local tmp-ID)
(2. mutation) check the new todo as completed (with the tmp-ID)
(2. mutation => optimistic update) show todo as completed
now connected to the server
???
can Apollo client replace the tmp-ID for the correct todo or how can I do it manually?
You can try this, but I don't think you will be able to retain the completed status of true on your server because you are sending a completeTodo mutation with a temporary id. There is now way for your server to know which todo you are referencing. Although this may give you two optimistic updates as you want.
const CREATE_TODO_MUTATION = gql`
mutation createTodo($todoContent: String!) {
createTodo(todoContent: $todoContent) {
id
createdAt
content
completed
}
}
`;
const COMPLETE_TODO_MUTATION = gql`
mutation completeTodo($id: String!) {
completeTodo(id: $id) {
id
createdAt
content
completed
}
}
`;
const TodosPageWithMutations = compose(
graphql(CREATE_TODO_MUTATION, {
props: ({ ownProps, mutate }) => ({
createTodo: content => mutate({
variables: { todoContent: content },
optimisticResponse: {
__typename: 'Mutation',
createTodo: {
__typename: 'Todo',
id: createTempID(),
content,
completed: false,
createdAt: new Date()
}
}
}),
}),
}),
graphql(COMPLETE_TODO_MUTATION, {
props: ({ ownProps, mutate }) => ({
completeTodo: todo => mutate({
variables: { id: todo.id },
optimisticResponse: {
__typename: 'Mutation',
completeTodo: {
__typename: 'Todo',
id: todo.id,
content: todo.content,
completed: true,
createdAt: todo.createdAt
}
}
}),
}),
})
)(TodosPage);

Cannot send aps to iOS using aws-sdk-js

I am trying to use aws-sdk-js to send push notification to iOS and Android device. It can send the notification message, but it is not the one I wanted. If i put badge and sound in the aps dictionary, the app should have a badge and play a sound. But it did not.
Xcode console output:
[aps: {
alert = "Test Message";
}]
javascript code:
var AWS = require('aws-sdk');
AWS.config.update({accessKeyId: '<key>', secretAccessKey: '<secrect>'});
AWS.config.update({region: 'ap-southeast-2'});
var sns = new AWS.SNS();
var payload = {
default: 'Test Message',
APNS: {
aps: {
alert: 'Test Message on iPhone',
badge: 1,
sound: "default"
},
}
};
payload.APNS = JSON.stringify(payload.APNS);
payload = JSON.stringify(payload);
var params = {
MessageStructure: 'json',
Message: payload,
Subject: 'Test push',
TargetArn: '<arn of the endpoint>'
};
sns.publish(params, function(err, data) {
if (err) console.log(err, err.stack);
else console.log(data);
});
code in application:didfinishlaunch,
let acceptAction = UIMutableUserNotificationAction()
acceptAction.identifier = "ACCEPT_IDENTIFIER"
acceptAction.title = NSLocalizedString("Accept", comment: "Accept")
acceptAction.activationMode = .Foreground
acceptAction.destructive = false
acceptAction.authenticationRequired = false
let deleteAction = UIMutableUserNotificationAction()
deleteAction.identifier = "DELETE_IDENTIFIER"
deleteAction.title = NSLocalizedString("Delete", comment: "Delete")
deleteAction.activationMode = .Foreground
deleteAction.destructive = true
deleteAction.authenticationRequired = false
let ignoreAction = UIMutableUserNotificationAction()
ignoreAction.identifier = "IGNORE_IDENTIFIER"
ignoreAction.title = NSLocalizedString("Ignore", comment: "Ignore")
deleteAction.activationMode = .Foreground
deleteAction.destructive = false
deleteAction.authenticationRequired = false
let messageCategory = UIMutableUserNotificationCategory()
messageCategory.identifier = "MESSAGE_CATEGORY"
messageCategory.setActions([acceptAction, deleteAction], forContext: .Minimal)
messageCategory.setActions([acceptAction, deleteAction, ignoreAction], forContext: .Default)
let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: (NSSet(array: [messageCategory])) as? Set<UIUserNotificationCategory>)
UIApplication.sharedApplication().registerForRemoteNotifications()
UIApplication.sharedApplication().registerUserNotificationSettings(notificationSettings)
and implement the protocol:
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
print(userInfo)
}
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
print(identifier)
completionHandler()
}
If you are using a developer profile for apns you should write APNS_SANDBOX instead of APNS
var payload = {
default: 'Test Message',
APNS_SANDBOX: {
aps: {
alert: 'Test Message on iPhone',
badge: 1,
sound: "default"
},
}
};