I have a row with value like this below:
{
"id": 1,
"token": "abcd"
}
How do I delete and save the value without "token" so it becomes this?
{
"id": 1
}
Do I need to first get the object, modify it then save back?
Maybe this will help you:
function patch(db, id, delta) {
return new Promise((resolve, reject) => {
const tx = db.transaction('mystore', 'readwrite');
tx.onerror = (event) => reject(event.target.error);
tx.oncomplete = () => resolve();
const store = tx.objectStore('mystore');
const request = store.get(id);
request.onsuccess = (event) => {
const object = event.target.result;
if (!object) {
reject(new Error(`No matching object for ${id}`));
return;
}
for (const prop in delta) {
if (typeof delta[prop] === 'undefined') {
delete object[prop];
} else {
object[prop] = delta[prop];
}
}
store.put(object);
};
});
}
async function dostuff() {
let db;
const id = 1;
const delta = {
token: undefined
};
try {
db = await connect();
await patch(db, id, delta);
} finally {
if (db) {
db.close();
}
}
}
Related
WebSocket doesn't send back a response despite the payLoad of the response is correct. The connection between front end and back end seems fine too. The boolean toggling inside the object array also works fine and does it's job. Any ideas why it isnt sending the JSON back to front end?
--------------------Front-end--------------------
const clientChangeVote = (c) => {
const payLoad = {
method: "changeVote",
clientId: gameData.clients[c].id,
gameId: gameData.id,
};
// voteValue: gameData.clients[c].voteReady,
ws.send(JSON.stringify(payLoad));
};
-----------------Back-end------------------------
if (result.method === "changeVote") {
const gameId = result.gameId;
const clientId = result.clientId;
games[gameId].clients
.filter((x) => x.id === clientId)
.forEach((vote) => (vote.voteReady = !vote.voteReady));
const updatedData = games[gameId].clients;
const payLoad = {
method: "changeVote",
updatedData: updatedData,
};
const game = games[gameId];
console.log(games);
game.clients.forEach((c) => {
console.log(payLoad);
c.connection.send(JSON.stringify(payLoad, getCircularReplacer()));
});
}
function getCircularReplacer() {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
}
-----------Inside the respone area. Im using React-----------
const [ws, setWs] = useState(new W3CWebSocket(URL));
useEffect(() => {
ws.onopen = () => {
console.log("Successful connection");
};
ws.onmessage = (message) => {
if (response.method === "changeVote") {
console.log("Vote received");
}
return () => {
ws.onclose = () => {
console.log("Connection closed");
setWs(new WebSocket(URL));
};
};
}, [ws.onmessage, ws.onopen, ws.onclose]);
Change ws.onmessage() :
ws.onmessage = (message) => {
let response = JSON.parse(message.data)
if (response.method === "changeVote") {
console.log("Vote received");
}
if not works add a comment.
I want to backup IndexedDB into json file, and restore it on another machine / browser.
the goal is to fully backup and import website session (localStorage, cookies etc...)
I think that dumpIndexedDb() function works correctly,
the problem occur when I try to get this data and restore it back using restoreIndexedDbDump(data). there's no errors.
but only few databases restored.
I'm pretty sure I was missed something with indexedDB api in the restore operation.
thanks in advance.
function dumpDB(dbName) {
return new Promise((resolve, reject) => {
var request = indexedDB.open(dbName)
request.onerror = e => reject(e)
request.onsuccess = (e) => {
var data = {} // { dbVersion: 1, oName: {keyPath: 'key', data: [{},{}]} }
var db = e.target.result
var dbVersion = db.version
data['dbVersion'] = dbVersion
data['objectStores'] = {}
var oStores = db.objectStoreNames
for (let osName of oStores) {
var transaction = db.transaction(osName, "readonly")
var oStore = transaction.objectStore(osName)
var keyPath = oStore.keyPath
data['objectStores'][osName] = {}
data['objectStores'][osName]['keyPath'] = keyPath
var request = oStore.getAll()
request.onerror = e => reject(e)
request.onsuccess = (e) => {
data['objectStores'][osName]['data'] = e.target.result
}
}
db.close()
resolve(data)
}
})
}
async function dumpIndexedDb() {
var data = {}
var dbs = await indexedDB.databases() // not working in firefox, tested in chrome.
for (let db of dbs) {
var dbData = await dumpDB(db.name)
data[db.name] = dbData
}
return data // {dbName: { dbVersion: 1, oName: {keyPath: 'key', data: [{},{}]} } }
}
function restoreObjectStore(dbName, version, oName, keyPath, data) {
return new Promise((resolve, reject) => {
request = window.indexedDB.open(dbName, version);
request.onerror = e => reject(e)
request.onupgradeneeded = function (e) {
try {
var db = e.target.result
if (keyPath) var objectStore = db.createObjectStore(oName, { keyPath: keyPath, autoIncrement: false })
else var objectStore = db.createObjectStore(oName, { autoIncrement: false })
for (let row of data) {
console.log(`adding row of ${oName}`)
}
objectStore.transaction.commit()
db.close()
resolve("ok")
} catch(e) {
reject(e)
}
}
})
}
async function restoreIndexedDbDump(data) {
for (let dbName in data) {
console.log(`deleting db ${dbName}`)
indexedDB.deleteDatabase(dbName)
for (let oStoreName in data[dbName]['objectStores']) {
let odata = data[dbName]['objectStores'][oStoreName]['data']
let dbVersion = data[dbName]['dbVersion']
if ( data[dbName]['objectStores'][oStoreName]['keyPath'] ) {
var keyPath = data[dbName]['objectStores'][oStoreName]['keyPath']
await restoreObjectStore(dbName, dbVersion, oStoreName, keyPath, odata)
}
else {
await restoreObjectStore(dbName, dbVersion, oStoreName, null, odata)
}
}
}
}
async function testBackupandRestore() {
var data = await dumpIndexedDb()
await restoreIndexedDbDump(data)
}
I'm trying to build a citation generator from json in an API with data about images, stored in key-value pairs. I can get the data to return to the screen, but it always includes undefined in the citation. Sample manifest returns undefined as the creator since that isn't listed in this particular record. How can I keep any undefined value from being returned? I've tried changing the forEach to map, filtering at allMetadata by string length, using if !== undefined at insertCitation, and versions of those in different spots in the code.
EDIT: updated to provide full code, including print to page
(function () {
'use strict';
const buildCitation = {
buildMetadataObject: async function (collAlias, itemID) {
let response = await fetch('/iiif/info/' + collAlias + '/' + itemID + '/manifest.json');
let data = await response.json()
let allMetadata = data.metadata
let citationData = {};
allMetadata.forEach(function (kvpair) {
if (kvpair.value == undefined) {
return false;
} else if (kvpair.label === 'Title') {
citationData.itemTitle = kvpair.value;
} else if (kvpair.label === 'Creator') {
citationData.itemCreator = kvpair.value;
} else if (kvpair.label === 'Repository') {
citationData.itemRepository = kvpair.value;
} else if (kvpair.label === 'Collection Name') {
citationData.itemCollection = kvpair.value;
} else if (kvpair.label === 'Owning Institution') {
citationData.itemOwning = kvpair.value;
} else if (kvpair.label === 'Date') {
citationData.itemDate = kvpair.value;
} else if (kvpair.label === 'Storage Location') {
citationData.itemStorage = kvpair.value;
}
return true;
});
return citationData;
},
insertCitation: function (data) {
var testTitle = data.itemTitle;
console.log(testTitle);
const itemCite = `Citation: "${data.itemTitle}," ${data.itemDate}, ${data.itemCreator}, ${data.itemCollection}, ${data.itemOwning}, ${data.itemStorage}, ${data.itemRepository}.`;
const citationContainer = document.createElement('div');
citationContainer.id = 'citation';
citationContainer.innerHTML = itemCite;
// CHANGED to innerHTML instead of innerText because you may want to format it at some point as HTML code.
if (testTitle) {
document.querySelector('.ItemView-itemViewContainer').appendChild(citationContainer);
}
}
}
document.addEventListener('cdm-item-page:ready', async function (e) {
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
document.addEventListener('cdm-item-page:update', async function (e) {
document.getElementById('citation').remove();
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
})();
I've simplified your program. The undefined is coming from the fact that there is no item with label Date
const mappings = {
Date: 'itemDate',
Title: 'itemTitle',
Creator: 'itemCreator',
Repository: 'itemRepository',
'Storage Location': 'itemStorage',
'Owning Institution': 'itemOwning',
'Collection Name': 'itemCollection',
}
async function buildMetadataObject(collAlias, itemID) {
let response = await fetch('https://teva.contentdm.oclc.org/iiif/info/p15138coll25/1421/manifest.json');
let data = await response.json()
return data.metadata.reduce(
(acc, { label, value }) => ({ ...acc, [ mappings[label] ]: value }),
{}
)
}
function insertCitation(data) {
var testTitle = data.itemTitle;
const fieldBlackList = ['itemTitle'];
const itemCite = `Citation: "${data.itemTitle}," ${
Object.values(mappings).reduce((acc, cur) => {
if (fieldBlackList.includes(cur)) return acc;
const value = data[cur];
return value ? [...acc, value] : acc
}, []).join(', ')
}.`;
console.log(itemCite);
}
//MAIN PROGRAM
(async() => {
const citationData = await buildMetadataObject();
insertCitation(citationData);
})()
I am not good at English. Successfully make recursive call function. However, there is a memory leak for some reason. The question is that there is no return. The purpose of this feature is to view and explore objects, arrays, and the rest of their properties.
How do I change the code if I have a problem with my return?
Thank you in advance.
I was able to know the cause of the memory leak through Google dev tools profiles.
function recursionProperty(prop, obj, fn) {
if (Array.isArray(obj)) {
obj.forEach(item => recursionProperty('files', item, fn));
} else if (obj instanceof Object) {
Object.keys(obj).forEach(prop => {
const value = obj[prop];
recursionProperty(prop, value, fn);
});
} else {
fn(prop, obj);
}
}
recursionProperty(null, {foo:'bar', baz: ['x','y']}, (prop, obj) => console.log(prop, obj));
my original code
import _ from 'lodash';
import fs from 'fs';
import path from 'path';
import errors from '#feathersjs/errors';
import connections from '../../../connections';
import config from '../../../config';
/**
* #param req
* #param serviceItem
* #param query
* #returns {Promise<any>}
*/
const getServicePromise = async (req, serviceItem, query) => {
let serviceName = serviceItem;
if (typeof serviceItem !== 'string') {
serviceName = `datasets/${serviceItem.name}`;
}
return new Promise(async (resolve, reject) => {
let result;
let objResult;
try {
result = await req.app.service(serviceName).find(query);
} catch (e) {
result = null;
console.log(e);
}
// console.log(result);
if (result) {
if (typeof serviceItem !== 'string') {
objResult = { [serviceItem.name]: result.data };
} else {
objResult = { [serviceName]: result.data };
}
resolve(objResult);
} if (result === null) {
objResult = { [serviceName]: [] };
resolve(objResult);
} else {
reject({
error: 'Not found data.'
});
}
});
};
/**
* 파일 경로 프로퍼티를 찾는 재귀함수
* 객체, 배열, 원시타입 등 여러 타입이 섞여있어도 사용 가능
* #param prop
* #param obj
* #param fn
*/
function recursionProperty(prop, obj, fn) {
if (Array.isArray(obj)) {
obj.forEach(item => recursionProperty('files', item, fn));
} else if (obj instanceof Object) {
Object.keys(obj).forEach(prop => {
const value = obj[prop];
recursionProperty(prop, value, fn);
});
} else {
fn(prop, obj);
}
}
/**
* #param req
* #returns {Promise<{any}>}
*/
const getService = async req => {
const result = {};
const serverPath = [];
const { sheet, dataset, icon } = req.data;
const iconState = Object.prototype.hasOwnProperty.call(req.data, 'icon');
const sheetState = Object.prototype.hasOwnProperty.call(req.data, 'sheet');
const datasetState = Object.prototype.hasOwnProperty.call(req.data, 'dataset');
try {
// sheets
if (sheetState) {
const itemList = ['sheets'];
if (sheet.length === 0) {
const query = {
query: {
},
};
await Promise.all(itemList.map(serviceItem => getServicePromise(req, serviceItem, query))).then(data => {
data.forEach(item => {
Object.assign(result, item);
});
});
} else if (sheet.length > 0) {
const query = {
query: {
_id: {
$in: sheet,
},
},
};
await Promise.all(itemList.map(serviceItem => getServicePromise(req, serviceItem, query))).then(data => {
data.forEach(item => {
Object.assign(result, item);
});
});
} else {
result.sheets = [];
}
} else {
result.sheets = [];
}
// 파일 경로 구하기
if (sheet) {
const { sheets } = result;
// const filePath = [];
recursionProperty('files', sheets, (prop, value) => {
// 여기서 원하는 필드인지 검색후 처리함
if (prop === 'fullPath' && fs.existsSync(path.join(__dirname, '../../../../files', value))) {
// filePath.push(path.join(__dirname, '../../../../files', value));
serverPath.push(value);
}
});
// const deduplication = Array.from(new Set(serverPath));
// const deduplicationPath = await deduplicationFilePath(deduplication);
//
// Object.assign(result, { filePath: deduplicationPath });
} else {
// result.filePath = [];
}
// files
if (sheet) {
const deduplicationFiles = Array.from(new Set(serverPath));
if (deduplicationFiles.length > 0) {
const query = {
query: {
$sort: {
createdAt: -1,
},
fullPath: {
$in: deduplicationFiles,
},
}
};
const files = await req.app.service('files').find(query);
Object.assign(result, { files: files.data });
} else {
result.files = [];
}
} else {
result.files = [];
}
// dataset
if (datasetState) {
const query = {
query: {
// $limit: 100000
}
};
if (dataset.length === 0) {
const meta = await req.app.service('datasets/_meta_').find();
Object.assign(result, { _meta_: meta });
const db = await connections.getConnection(connections.DATASETS_DB);
const collectionNames = _.filter(await db.client.db(config.database_datasets.dbname).listCollections().toArray(), o => o.name !== '_meta_');
// collectionNames.forEach(str => {
// const detectA = iconvDetect.detect(Buffer.from(str.name));
// console.log('collection type', str.name, detectA);
// });
await Promise.all(meta.map(serviceItem => {
// const detectA = iconvDetect.detect(Buffer.from(serviceItem.key));
// console.log('meta type', serviceItem.key, detectA);
return getServicePromise(req, `datasets/${serviceItem.key}`, query);
})).then(data => {
Object.assign(result, { datasets: data });
});
} else if (dataset.length > 0) {
const metaQuery = {
query: {
$sort: {
createdAt: -1,
},
key: {
$in: dataset
}
}
};
const meta = await req.app.service('datasets/_meta_').find(metaQuery);
// console.log(meta);
Object.assign(result, { _meta_: meta });
await Promise.all(dataset.map(serviceItem => getServicePromise(req, `datasets/${serviceItem}`, query))).then(data => {
const d = Array.from(new Set(data));
const s = d.filter(item => item !== null);
if (d.length > 0) {
Object.assign(result, { datasets: s });
} else {
result.datasets = [];
result._meta_ = [];
}
});
} else {
result.datasets = [];
result._meta_ = [];
}
} else {
result.datasets = [];
result._meta_ = [];
}
if (iconState) {
const itemList = ['iconCategories', 'iconItems'];
const query = {};
if (icon.length === 0) {
await Promise.all(itemList.map(serviceItem => getServicePromise(req, serviceItem, query))).then(data => {
data.forEach(item => {
Object.assign(result, item);
});
});
}
} else {
result.iconCategories = [];
result.iconItems = [];
}
} catch (e) {
throw new errors.BadRequest('The data is invalid.', e);
}
return result;
};
export default getService;
There is most likely no memory leak in your code. Yes, recursive functions can be more memory aggressive than normal functions, because the call stack can grow very quickly, but remember that all functions will implicitly return even if there is no return statement. (Imagine that there is always a return undefined; line at the end of all your functions)
When doing a recursion, call stack will grow until you reach the bottom of a recursion branch (no function returns until then). Once the recursion branch end is reached, in your case this happens anytime you reach your else block, call stack will 'collapse' and all functions preceding will 'return'.
Memory will ultimately be freed by garbage collection as required.
so I have a selector that contains multiple options and below that I have a paragraph the content of which would change in accordance to the selected option in the select menu. I used find method to loop through the array and return the element(which is an object) that satisfy find function. however there is a problem with find method that I could not figure out.
'use strict';
{
function fetchJSON(url, cb) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';
xhr.onload = () => {
if (xhr.status < 400) {
cb(null, xhr.response);
} else {
cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
}
};
xhr.onerror = () => cb(new Error('Network request failed'));
xhr.send();
}
function createAndAppend(name, parent, options = {}) {
const elem = document.createElement(name);
parent.appendChild(elem);
Object.keys(options).forEach(key => {
const value = options[key];
if (key === 'text') {
elem.textContent = value;
} else {
elem.setAttribute(key, value);
}
});
return elem;
}
function createLI(root, sel, options = []) {
const select = document.createElement(sel);
root.appendChild(select);
select.innerHTML = options.sort().map(repo => `<option value="${repo.id}">${repo.name}</option>`).join('\n');
select.addEventListener("change", function () {
const chosenRepoId = this.value;
const selectedRepo = options.find(repo => repo.id === chosenRepoId);
document.getElementById('repoInfo').innerHTML = selectedRepo.description;
});
}
function main(url) {
fetchJSON(url, (err, data) => {
const root = document.getElementById('root');
if (err) {
createAndAppend('div', root, { text: err.message, class: 'alert-error' });
} else {
// createAndAppend('pre', root, { text: JSON.stringify(data, null, 2) });
createLI(root, 'select', data);
}
});
}
const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
window.onload = () => main(HYF_REPOS_URL);
}
````js
this.value returns string.
In the comparison - const selectedRepo = options.find(repo => repo.id === chosenRepoId);
you are using strict equality operator and your chosenRepoId is numeric. So, first convert the selected value to number (use + or parseInt).
const chosenRepoId = +this.value;
const selectedRepo = options.find(repo => repo.id === chosenRepoId);