How do I delete a string object element stored in Redis? - node.js

I am trying to delete an entire object stored in Redis using LREM, but I don't think I am doing it right, below is the code I tried:
GraphQL mutation:
deleteImage: async(_,args) => {
let data = await client.lrem("postedImagesList",0,JSON.stringify(args.id));
return data
}
postedImagesList is a redis collection of all the object elements stringified:
1) "{\"id\":\"aadc8456-a5c9-46b9-a58c-670446d95c70\",\"url\":\"chas\",\"description\":\"asd\",\"posterName\":\"asda\",\"binned\":false,\"userPosted\":true}"
2) "{\"id\":\"a24d6d1b-224f-400d-8b84-dac83d8eaf92\",\"url\":\"ihir\",\"description\":\"helped\",\"posterName\":\"bhi\",\"binned\":false,\"userPosted\":true}"
I am given the id as an argument and I have to delete the entire object, how can I do so? I am adding the elements using lpushasync.

Please see the LREM docs.
LREM key count element
The element argument has to have an exact match, so you can't match by ID.
You might want to consider using the RedisJSON using the JSON.DEL you should be easily achieve what you're looking for.

Related

Transforming large array of objects to csv using json2csv

I need to transform a large array of JSON (that can have over 100k positions) into a CSV.
This array is created directly in the application, it's not the result of an uploaded file.
Looking at the documentation, I've thought on using parser but it says that:
For that reason is rarely a good reason to use it until your data is very small or your application doesn't do anything else.
Because the data is not small and my app will do other things than creating the csv, I don't think it'll be the best approach but I may be misunderstanding the documentation.
Is it possible to use the others options (async parser or transform) with an already created data (and not a stream of data)?
FYI: It's a nest application but I'm using this node.js lib.
Update: I've tryied to insert with an array with over 300k positions, and it went smoothly.
Why do you need any external modules?
Converting JSON into a javascript array of javascript objects is a piece of cake with the native JSON.parse() function.
let jsontxt=await fs.readFile('mythings.json','uft8');
let mythings = JSON.parse(jsontxt);
if (!Array.isArray(mythings)) throw "Oooops, stranger things happen!"
And, then, converting a javascript array into a CSV is very straightforward.
The most obvious and absurd case is just mapping every element of the array into a string that is the JSON representation of the object element. You end up with a useless CSV with a single column containing every element of your original array. And then joining the resulting strings array into a single string, separated by newlines \n. It's good for nothing but, heck, it's a CSV!
let csvtxt = mythings.map(JSON.stringify).join("\n");
await fs.writeFile("mythings.csv",csvtxt,"utf8");
Now, you can feel that you are almost there. Replace the useless mapping function into your own
let csvtxt = mythings.map(mapElementToColumns).join("\n");
and choose a good mapping between the fields of the objects of your array, and the columns of your csv.
function mapElementToColumns(element) {
return `${JSON.stringify(element.id)},${JSON.stringify(element.name)},${JSON.stringify(element.value)}`;
}
or, in a more thorough way
function mapElementToColumns(fieldNames) {
return function (element) {
let fields = fieldnames.map(n => element[n] ? JSON.stringify(element[n]) : '""');
return fields.join(',');
}
}
that you may invoke in your map
mythings.map(mapElementToColumns(["id","name","element"])).join("\n");
Finally, you might decide to use an automated for "all fields in all objects" approach; which requires that all the objects in the original array maintain a similar fields schema.
You extract all the fields of the first object of the array, and use them as the header row of the csv and as the template for extracting the rest of the elements.
let fieldnames = Object.keys(mythings[0]);
and then use this field names array as parameter of your map function
let csvtxt= mythings.map(mapElementToColumns(fieldnames)).join("\n");
and, also, prepending them as the CSV header
csvtxt.unshift(fieldnames.join(','))
Putting all the pieces together...
function mapElementToColumns(fieldNames) {
return function (element) {
let fields = fieldnames.map(n => element[n] ? JSON.stringify(element[n]) : '""');
return fields.join(',');
}
}
let jsontxt=await fs.readFile('mythings.json','uft8');
let mythings = JSON.parse(jsontxt);
if (!Array.isArray(mythings)) throw "Oooops, stranger things happen!";
let fieldnames = Object.keys(mythings[0]);
let csvtxt= mythings.map(mapElementToColumns(fieldnames)).join("\n");
csvtxt.unshift(fieldnames.join(','));
await fs.writeFile("mythings.csv",csvtxt,"utf8");
And that's it. Pretty neat, uh?

Add new item to Realtime Database array

How I could append an element to an array like that ?.
Adding an item to an array structure like that, requires three steps:
Read the existing data.
Determine the key of the new item.
Write the new item.
In code that'd be something like:
const ref = admin.database().ref("javascript");
ref.once("value").then((snapshot) => {
let numChildren = parseInt(snapshot.numChildren());
ref.child(""+(numChildren+1)).set(4);
});
Note that this type of data structure is fairly non-idiomatic when it comes to Firebase, and I recommend reading:
Best Practices: Arrays in Firebase.

OrderBy and StartAt with two different fields firestore

In my app, I have comments that have a field value of threadCommentCount. I want to order the comments using orderBy threadCommentCount descending and then have pagination continue this using startAfter(lastThreadCommentCount). The problem is when threadCommentCount is 0, which is a lot of them, it will return and the same data every time since it starts at 0 everytime. Here is the query:
popularCommentsQuery = db
.collection('comments')
.where('postId', '==', postId)
.orderBy('threadCommentCount', 'desc')
.startAfter(startAfter)
.limit(15)
.get()
This will return the same comments everytime once threadComment count is 0. I'm unable to send the last document snapshot because im using cloud functions and I dont want to send the documentSnapshot in a get query parameter. I don;t really care how the comments are ordered after threadCommentCount is 0, I just need to not get any duplicates. Any help is great!
All Firestore queries have an implicit orderBy("__name__", direction) to resolve any ties between documents that have the same values for the other named orderBy fields. This makes the final sort order stable. But it also enables you to pass another argument to startAfter to provide the document ID of the anchor document that you wish to use for the purpose of pagination.
.startAfter(lastThreadCommentCount, lastDocumentId)
Between these two values, you should be able to uniquely identify the document in the result set to start the next page.
so, I was trying OrderBy and StartAfter with two different fields(time,key) in firestore to establish pagination in flastList.
Key point is that we can pass document snapshot to define the query cursor [reference]
Here is how I managed to do it.
step 1: get the document Id(which is auto generated by firebase) with where() [reference]
const docRef = firestore().collection('shots').where('key','==','custom_key')
const fbDocIdGeneratedByFirebase= await docRef.get().docs[0].id;
step 2: get document snapshot with firebase generated document Id (which we got in the 1st step)
const docRef2= firestore().collection('shots').doc(fbDocIdGeneratedByFirebase)
const snapshot = await docRef2.get();
step 3: pass the snapshot got in step 2 to startAfter() so that the cursor will point there [reference]
let additionalQuery = firestore().collection('shots')
.orderBy("time", "desc")
.startAfter(snapshot)
.limit(this.state.limit)
let documentSnapshots = await additionalQuery.get(); // you know what to do next
...
Can you Improve the solution??

How to get object x or y in nested document

I know this has been asked before but I can't seem to find the answer, I want to get data/object in the nested array.
show image problem
schedule = await Schedule.findById({_id:'5b496ec3444152122c8d839e'})
console.log(schedule.datalayout.section.data.x)
If you want to get the specified field in the image, you need to determine field index in the array as down below:
console.log(schedule.datalayout.section[0].data[0].x)
And also, If you want to get all of the x fields in the data array, you need to write something like this:
for(let singleData of schedule.datalayout.section[0].data){
console.log(singleData.x)
}
// for using 'of' keyword, your function must be a async function.

Firebase Invalid document reference. Document references must have an even number of segments

What is wrong with this query?
const db = firebase.firestore()
const query = db.doc(this.props.user.uid).collection('statements').orderBy('uploadedOn', 'desc').limit(50)
I get the following error:
Uncaught Error: Invalid document reference. Document references must have an even number of segments, but FrMd6Wqch8XJm32HihF14tl6Wui2 has 1
at new FirestoreError (index.cjs.js:346)
at Function.DocumentReference.forPath (index.cjs.js:15563)
at Firestore.doc (index.cjs.js:15368)
at UploadStatementPresentation.componentWillMount (UploadStatementPage.jsx:61)
at UploadStatementPresentation.componentWillMount (createPrototypeProxy.js:44)
at callComponentWillMount (react-dom.development.js:6872)
at mountClassInstance (react-dom.development.js:6968)
at updateClassComponent (react-dom.development.js:8337)
at beginWork (react-dom.development.js:8982)
at performUnitOfWork (react-dom.development.js:11814)
Since you haven't described what exactly you're trying to query, I'll just point out that all documents must be in a collection, without exception. So, if you say this:
db.doc(this.props.user.uid)
Firestore assumes that the string you're passing to doc() contains both the collection and document id separated by a slash. But this seems to be highly unlikely in your case. You need to determine which collection the uid is in, and use that first when you build the reference to the collection you want to query. Assuming that you do have a statements subcollection in the uid document, and that some other collection contains the uid document, you'll have to specify the full path like this:
db.collection('that-other-collection').doc(this.props.user.uid).collection('statements')
Of course, only you know the actual structure of your data.
If you want to get a collection of documents with querying, you don’t have to specify a document id. Below code should work in this case.
const query = db.collection('statements').orderBy('uploadedOn', 'desc').limit(50)
Or if you want to get the document, you can pass the document id to doc() method. In that case, the code should be.
const query = db.collection('statements').doc(this.props.user.uid)
For more details about querying firestorm data: https://firebase.google.com/docs/firestore/query-data/get-data?authuser=0
For others having this issue, make sure that no document reference has an empty string.
I had this issue when using a get method with uid input as below and forgot to check if uid is empty
private fun getFullRef(uid: String): CollectionReference {
return ref.document(uid).collection(FireContact.SUB_PATH)
}

Resources