Empty object for Firebase server timestamp - node.js

I´m getting an empty object for the admin.firestore.FieldValue.serverTimestamp(), below is the screenshot of the document being stored in Firestore:
Here´s the code for creating the message object (that corresponds to the screenshot above):
import {Message} from "./Message";
import {MessageType} from "./MessageType";
import * as admin from "firebase-admin";
export class TextMessage extends Message {
constructor(objectID: string,
content: string,
authorName: string,
authorID: string,
authorPhotoUrl: string,
createdAt: FirebaseFirestore.FieldValue = admin.firestore.FieldValue.serverTimestamp()) {
super(objectID,
content,
authorName,
authorID,
authorPhotoUrl,
MessageType.text,
createdAt,)
}
}
Here´s where I create the TextMessage object:
const message: TextMessage = new TextMessage(
messageID,
"Cualquier consulta escríbeme un mensaje y estaré para ayudarte",
SUPPORT_NAME,
SUPPORT_USER_ID,
defaultProfilePicture
)
And here´s the Firebase function code in which the code from above is being used:
// Create the chat
const createChatPromise =
firestoreDB
.collection("Chats")
.doc(chatID)
.collection("Messages")
.add(JSON.parse(JSON.stringify(message)))
// Return the method when both functions are finished
return Promise.all(
[
addToFirestorePromise,
addToAlgoliaPromise,
emailPromise,
createCurrentUserInboxPromise,
createSupportInboxPromise,
createChatPromise, ==> This is the promise from above
addUsersIDsPromise
]
).catch(error => functions.logger.log("The error is: " + error.message))
From the object´s documentation:
Returns a sentinel used with set(), create() or update() to include a server-generated timestamp in the written data.
Returns:
The FieldValue sentinel for use in a call to set(), create() or update().
However, I´m using the add function, I don´t know if this is the reason why is not working.
NOTE: I´m using the following versions for firebase admin and functions:
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.7.0",

It's not clear to me why you are using both stringify and parse together like this:
JSON.parse(JSON.stringify(message))
The stringify will destroy the token that internally represents the server timestamp. You're supposed to pass the object to store in Firestore directly to add() or set() - never stringify it.

Related

Firebase does not recognize document path

So I have the following request with which I am trying to do the following:
Look for a collection with the name 'questionnaires'
Look at a specific document with id, given by the parameter of the function
Take the reference of a collection 'questions' within this document
public async getQuestionnaire(
questionnaireId: string,
): Promise<FirebaseFirestore.CollectionReference<DocumentData>> {
const questionsCollection = await getFirestore().collection(
'questionnaires/{questionnaireId}/questions/',
);
return questionsCollection;
}
I tried both by obtaining the reference in one line or seperating it the following way:
public async getQuestionnaire(
questionnaireId: string,
): Promise<FirebaseFirestore.CollectionReference<DocumentData>> {
const questionnairesCollection =
getFirestore().collection('questionnaires');
const desiredQuestionnaire = questionnairesCollection.doc(questionnaireId);
const questions = desiredQuestionnaire.collection('questions');
return questions;
}
The method is called from the following get request handler:
#Get('/firebase/questionnaire/:questionnaireId')
#OpenAPI({ summary: 'Return a questionnaire' })
async getQuestionnaire(#Param('questionnaireId') questionnaireId: string) {
const questionsRef = await this.firebaseService.getQuestionnaire(
questionnaireId,
);
return { data: questionsRef };
}
The interesting thing is that if I print out the reference, I get exactly what I want. However when I try to return it, I get the following error:
[GET] /firebase/questionnaire/3iz5K3hsVvaFBwkyzd57 >> StatusCode:: 500,
Message:: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.

Redux unexpected behaviour | create empty object if not found

I am debugging an app, there is an existing redux reducer which sets some data of store object. Now when i dispatch action for this reducer before the relevant object is initialised it still works and create an empty object. This works on our deployment server and do crash on my local machine with correct error that "map is undefined on null". Why is it creating an empty object and not crashing on deployment server and if it is creating an object why is it not assigning the data we pass to it. My reducer is
case ACTIONS.SET_LOCAL_WEIGHTS: {
const { weight } = action;
const drafts = fromJS(state.getIn(['draftData', 'rows']));
const setWeight = drafts.map((row: any) => {
row.data.weight = weight[row.id].weight;
return row;
});
return state
.setIn(['draftData', 'rows'], setWeight)
.setIn(['draftData', 'total'], setWeight.length);
}
It creates: draftData: {} when rows and total is also provided. I have tried it on node 15 and 12 for checking any anomaly on map function.
I get error Cannot read property 'map' of undefined on your code if the initial state doesn't have a property state.draftData.rows. I don't see anywhere where you would be creating an empty object.
The immutable.js fromJS method will create a List if called with an array from state.draftData.rows. But if it is called with undefined then it returns undefined instead of a collection with a .map() method.
I also don't think that you need to be calling fromJS if the rows object is never converted toJS, but it might depend on your initial state.
This code should work. It uses the existing List from state if it exists, or creates an empty List otherwise.
const drafts = state.getIn(["draftData", "rows"]) ?? fromJS([]);
The assignment in row.data.weight = weight[row.id].weight seems like a mutation of state.
I tried to rewrite this, but it seems strange to me that your code doesn't do anything with the weights in the payload unless their index/key matches one that's already in the state.
import { fromJS, List, Map } from "immutable";
interface Row {
data: {
weight: number;
};
id: number;
}
const reducer = (state = Map(), action) => {
switch (action.type) {
case ACTIONS.SET_LOCAL_WEIGHTS: {
const { weight } = action;
const drafts: List<Row> =
state.getIn(["draftData", "rows"]) ?? fromJS([]);
const setWeight = drafts.reduce(
(next, row, index) =>
next.setIn([index, "data", "weight"], weight[row.id]?.weight),
drafts
);
return state
.setIn(["draftData", "rows"], setWeight)
.setIn(["draftData", "total"], setWeight.size);
}
default:
return state;
}
};

How to use json data that I receive from MongoDB in flutter?

I want to use the json data that I receive from mongodb on to my flutter client.
The format of my mongodb document is:
{
"_id":"2020-10-10 18:35:19.465085",
"classhours":"56",
"sleephours":"56",
"studyhours":"56",
"activity":"9.0"
}
I am able to fetch data like this:
db = await mongo.Db.create(
"mongodb+srv://id:pass#cluster0.qkmvt.mongodb.net/students?retryWrites=true&w=majority");
await db.open();
print('DB Connected');
coll = db.collection(widget.uid);
print(coll);
var response = await coll.find();
print(response);
I am able to print all the documents in the console using this. How to use the response in the client ui like for text.Can someone help me with it?
You can use FutureBuilder widget to set Text widget with value that you receive from asynchronous calls.
For more info refer: https://flutter.dev/docs/cookbook/networking/fetch-data
You can convert the JSON response to a Map. Here's an example
import 'dart:convert';
void main() {
var db="{\"_id\":\"2020-10-10 18:35:19.465085\",\r\n\"classhours\":\"56\", \r\n \"sleephours\":\"56\",\r\n\"studyhours\":\"56\",\r\n\"activity\":\"9.0\"\r\n}";
Map<String, dynamic> db_map=jsonDecode(db);
print(db_map['_id']);
}
Or you can make a Plain Old Dart Object of the response using Quicktype. Here is what you would get
// To parse this JSON data, do
//
// final dbModel = dbModelFromJson(jsonString);
import 'dart:convert';
DbModel dbModelFromJson(String str) => DbModel.fromJson(json.decode(str));
String dbModelToJson(DbModel data) => json.encode(data.toJson());
class DbModel {
DbModel({
this.id,
this.classhours,
this.sleephours,
this.studyhours,
this.activity,
});
DateTime id;
String classhours;
String sleephours;
String studyhours;
String activity;
factory DbModel.fromJson(Map<String, dynamic> json) => DbModel(
id: DateTime.parse(json["_id"]),
classhours: json["classhours"],
sleephours: json["sleephours"],
studyhours: json["studyhours"],
activity: json["activity"],
);
Map<String, dynamic> toJson() => {
"_id": id.toIso8601String(),
"classhours": classhours,
"sleephours": sleephours,
"studyhours": studyhours,
"activity": activity,
};
}
After you receive your response, just use
DbModel model=DbModel.fromJson(json.decode(db));
print(model._id); // Access whatever variables you want
EDIT 1: In my example, I have hardcoded the response as a String variable db. This is equivalent to the response variable as mentioned in the question

How to import an object and run a function for all properties in module?

I created a module to store an object with some properties containing array of strings. Once it is imported, I want to get a sample of this array (eg: using lodash / sample). So I do not have to use the 'sample' method every time the module is imported and a property is referenced. Obs.: I want to reference an object and a property, not a function.
/store.js
export default {
foo: [
`This is the first message`,
`This is the second message`,
`This is the third message`
],
bar: [
`This is the message one`,
`This is the message two`,
`This is the message three`
]
};
I want to avoid this:
/file.js
import store from './store';
import sample from 'lodash/sample';
const msg = sample(store.foo);
console.log(msg); // e.g: This is the second message
and use something like this:
/file.js
import store from './store';
const msg = store.foo;
console.log(msg); // e.g: This is the first message

How can I access Azure document db node js TriggerType definition?

I get TriggerType undefined when the following trigger is uploaded to an azure document collection:
'mytriggerTrigger': {
id: 'triggerid',
serverScript: function Foo() {
// code omitted
},
triggerType: TriggerType.Pre,
triggerOperation : TriggerOperation.Create
}
You'll need to import DocumentBase object, then you can access these properties.
var documentdb = require('documentdb'),
DocumentClient = documentdb.DocumentClient,
DocumentBase = documentdb.DocumentBase;
'mytriggerTrigger': {
id: 'triggerid',
serverScript: function Foo() {
// code omitted
},
triggerType: DocumentBase.TriggerType.Pre,
triggerOperation : DocumentBase.TriggerOperation.Create
}

Resources