I have a node server running where I want to listen to a collection update and get the added data.
My solution was using db.collection("posts").onSnapshot to listen to a update and to get the latest I would order by date.
db.collection("posts").onSnapshot(async () => {
const newPost = await db
.collection("posts")
.orderBy("date", "desc")
.limit(1)
.get()
.data();
console.log(newPost);
});
but .data() is not a function so I don't know how to retrive the data. I did a little debbuging and couldn't find any keys in the object that would give me the data from the post.
This is what it returns without .data()
QuerySnapshot$1 {
_delegate:
QuerySnapshot {
_firestore:
FirebaseFirestore$1 {
_persistenceKey: '[DEFAULT]',
_settings: [FirestoreSettings],
_settingsFrozen: true,
_app: [FirebaseAppImpl],
_databaseId: [DatabaseId],
_credentials: [FirebaseCredentialsProvider],
_queue: [AsyncQueue],
_firestoreClient: [FirestoreClient] },
_userDataWriter: UserDataWriter { firestore: [Firestore] },
_snapshot:
ViewSnapshot {
query: [QueryImpl],
docs: [DocumentSet],
oldDocs: [DocumentSet],
docChanges: [Array],
mutatedKeys: [SortedSet],
fromCache: false,
syncStateChanged: true,
excludesMetadataChanges: false },
metadata:
SnapshotMetadata { hasPendingWrites: false, fromCache: false },
query:
Query {
_converter: null,
_query: [QueryImpl],
type: 'query',
firestore: [FirebaseFirestore$1] } },
_firestore:
Firestore {
_delegate:
FirebaseFirestore$1 {
_persistenceKey: '[DEFAULT]',
_settings: [FirestoreSettings],
_settingsFrozen: true,
_app: [FirebaseAppImpl],
_databaseId: [DatabaseId],
_credentials: [FirebaseCredentialsProvider],
_queue: [AsyncQueue],
_firestoreClient: [FirestoreClient] },
_persistenceProvider: IndexedDbPersistenceProvider {},
INTERNAL: { delete: [Function: delete] },
_appCompat:
FirebaseAppImpl {
firebase_: [Object],
isDeleted_: false,
name_: '[DEFAULT]',
automaticDataCollectionEnabled_: false,
options_: [Object],
container: [ComponentContainer] } } }
Your code will have to first await the result of the get(), then reach into the returned QuerySnapshot to find the document data. Note that a QuerySnapshot contains zero or more documents, and you will need to use its API to find out if there are any documents returned. Even if you think it will just return 1 document, you still need to reach into the result set to find that one document.
const newPost = await db
.collection("posts")
.orderBy("date", "desc")
.limit(1)
.get();
// newPost is a QuerySnapshot
if (newPost.size > 0) {
const data = newPost.docs[0].data();
// do what you want with the document data
}
else {
// figure out what you want to do if no documents were queried
}
Related
I have a collection called 'users' in Firestore, and it is structured like this
users
->
document
-> email, name
db.collection('users').get().then(snapshot => {
snapshot.docs.forEach(doc => {
console.log(doc)
});
});
This code is supposed to fetch all the documents in the collection (there are about 15), but when I run it, I get a long error (below)
QueryDocumentSnapshot {
_firestore: Firestore {
_delegate: Firestore$1 {
type: 'firestore',
_persistenceKey: '[DEFAULT]',
_settings: [FirestoreSettingsImpl],
_settingsFrozen: true,
_app: [FirebaseAppImpl],
_databaseId: [DatabaseId],
_credentials: [FirebaseCredentialsProvider],
_queue: [AsyncQueueImpl],
_firestoreClient: [FirestoreClient]
},
_persistenceProvider: IndexedDbPersistenceProvider {},
INTERNAL: { delete: [Function: delete] },
_appCompat: FirebaseAppImpl {
firebase_: [Object],
isDeleted_: false,
name_: '[DEFAULT]',
automaticDataCollectionEnabled_: false,
options_: [Object],
container: [ComponentContainer]
}
},
_delegate: QueryDocumentSnapshot$1 {
_firestore: Firestore$1 {
type: 'firestore',
_persistenceKey: '[DEFAULT]',
_settings: [FirestoreSettingsImpl],
_settingsFrozen: true,
_app: [FirebaseAppImpl],
_databaseId: [DatabaseId],
_credentials: [FirebaseCredentialsProvider],
_queue: [AsyncQueueImpl],
_firestoreClient: [FirestoreClient]
},
How should I fetch documents properly without this error?
Firebase version - 8.2.3
Thanks
This is not an error: With your code you are actually printing the QueryDocumentSnapshot Objects in your console.
You should call the data() method to get the documents data, as follows:
db.collection('users').get().then(snapshot => {
snapshot.docs.forEach(doc => {
console.log(doc.data()); // Or console.log(JSON.stringify(doc.data()));
});
});
Also note that a QuerySnapshot has a forEach() method and therefore you could do:
db.collection('users').get().then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data());
});
});
I am trying to make API for my invoices data in which there are some boolean values on that basis I want to search those invoices. Like there are some invoice marked as 'payment received' and I want to search those invoice in mongoDB
I am using:
Backend - ExpressJS
Data Base - MongoDB
Route:
app.get("/api/invoice/search", async (req, res) => {
try {
const invoice = await Invoice.find({
isDispatched: true, // This is dynamic data I want to search this data from req.body, this is // for testing
});
res.status(200).json({
success: true,
totalInvoices: invoice.length,
invoice,
});
} catch (err) {
console.log(err);
}
});
Output, I am getting all the data instead of the those filtered with query.
I want to search multiple fields here I am using $or for this but its not working.
app.get("/api/invoice/search", async (req, res) => {
try {
const invoice = await Invoice.find({
$or: [
{
isDispatched: { $exists: true }, //This has to be dynamic data from req.data
},
{
paymentPending: { $exists: true }, //This has to be dynamic data from req.data
},
],
});
res.status(200).json({
success: true,
totalInvoices: invoice.length,
invoice,
});
} catch (err) {
console.log(err);
}
});
Output is random like sometime I get few data which has both true and false data.
I have tried removing $exists, adding $regex but didn't worked.
I have tried removing $exists, adding $regex but didn't worked.
My understanding of the question:
The result of the query sometimes returns values where isDispatched data exists and paymentPending does not. Likewise, with paymentPending data existing and isDispatched data not.
Based on this understanding there might be two problems.
First Possible Issue:
If the above is correct it looks like you aren't really trying to use an $or. Try using the following as your query to see if your results are as expected.
{
isDispatched: { $exists: true },
paymentPending: { $exists: true }
}
Explanation: $or is going to return any values that match either case.
Second Possible Issue:
The $exists only checks that the value is in the document; it will match a null value. So, you may be expecting null fields to not exist.
{
isDispatched: { $exists: true, $ne: null },
paymentPending: { $exists: true, $ne: null }
}
I am using prisma with mongoDb for the first time and I want to update a boolean value stored in a collection, but I am not able to find a way/query to update the value from true to false or vise versa...:(
const updateUser = await prisma.user.update({
where: {
userToken: token,
},
data: {
isOnline: true,
},
})
I have this 'isOnline' stored as false default and this is what I have tried wrt prisma official documentation, but this did not worked for me
I think you are looking for set
const updateUser = await prisma.user.update({
where: {
userToken: token,
},
data: {
isOnline: {
set: true
},
},
})
Since true and false values could be mistaken as a special instruction in "prisma logics", the response from #Fastnligth should be the correct one -did't tried that though-.
Since Prisma ORM implemented MongoDB as an after thought, some of these functionalities might "seem a bit off".
I've arrived here trying to update an embedded field without updating the whole document, just the given field.
Leaving my two cents in case somebody else is having the same sailing over google ⛵️
You can do that as follows
const order = await prisma.order.update({
where: {
id: 'some-object-id',
},
data: {
shippingAddress: {
// Update just the zip field
update: {
zip: '41232',
},
},
},
})
official docs: https://www.prisma.io/docs/concepts/components/prisma-client/composite-types
To clarify, I'm trying to build a feature to let my users manage the notifications and emails they receive.
In order to do that, I decided to implement an object with several objects within itself.
Everything seems to make sense in my head but I'm here because I found a problem and I can not solve it by myself.
Here is the problem:
I have two endpoints and two function, each endpoint calls their respective function. Everytime I make a call to any of the two endpoints, said call updates not only the data on its endpoint but in the other endpoint as well, do I explain myself?
Let's put it this way, this is endpoint A {{URL}}/api/v1/auth/updateemailnotifications and this ednpoint B {{URL}}/api/v1/auth/updatenotifications. No matter which one is called, it updates the other's endpoint data as well.
ENDPOINT A:
const user = await User.findByIdAndUpdate(
{
_id: req.user._id
},
{
$set: {
settings: {
notifications: {
comments: {
fromBlogNotification: req.body.fromBlogNotification,
fromPostNotification: req.body.fromPostNotification,
fromVideoNotification: req.body.fromVideoNotification,
fromMediaNotification: req.body.fromMediaNotification,
fromProducerNotification: req.body.fromProducerNotification,
fromJobNotification: req.body.fromJobNotification,
fromCommentNotification: req.body.fromCommentNotification
},
news: {
fromBlogNewsNotification: req.body.fromBlogNewsNotification,
fromProducerNewsNotification:
req.body.fromProducerNewsNotification,
fromUserNewsNotification: req.body.fromUserNewsNotification
}
}
}
}
},
{
new: true,
runValidators: true,
// setDefaultsOnInsert: true
}
);
ENDPOINT B:
const user = await User.findByIdAndUpdate(
{
_id: req.user._id
},
{
$set: {
settings: {
emails: {
comments: {
fromBlogComments: req.body.fromBlogComments,
fromPostComments: req.body.fromPostComments,
fromVideoComments: req.body.fromVideoComments,
fromMediaComments: req.body.fromMediaComments,
fromProducerComments: req.body.fromProducerComments,
fromJobComments: req.body.fromJobComments,
fromCommentComments: req.body.fromCommentComments
}
}
}
}
},
{
new: true,
runValidators: true,
// setDefaultsOnInsert: true
}
);
Hopefully you guys can help me solve this, thanks!.
In your code, you are replacing the whole settings with the new value. To update specific field in settings, you need to use dot notation:
const user = await User.findByIdAndUpdate(
{ _id: req.user._id },
{
$set: {
'settings.notifications': {
...
}
}
},...
I have a controller which looks up a character, and then does some stuff with it, the controller looks like:
router.post('/profile/characters', async ctx => {
try {
ctx.type = 'json';
let req = ctx.request;
if (!('charname' in req.body) || !('charserver' in req.body)) {
return res.json({
'success': false,
error: 'You are missing either the character name, or server'
});
}
let foundChar = await new Promise((res, rej) => {
bnet.wow.character.aggregate({
origin: 'us',
realm: req.body.charserver,
name: req.body.charname,
fields: ['items', 'talents']
}, (err, charData) => {
if (err) {
console.log(err);
return rej(err);
}
return res(charData);
});
});
if ('status' in foundChar) {
if (foundChar.status === 'nok') {
return ctx.body = {
'success': false,
error: 'There was an error looking up your character, please ensure its a US character, and has been logged into recently'
};
}
}
foundChar.items.level = foundChar.level;
foundChar.items.class = foundChar.class;
foundChar.items.thumbnail = foundChar.thumbnail;
foundChar.items.name = foundChar.name;
let {
items, talents
} = foundChar;
let specF = talents.find(x => x.selected) || {};
let charData = {
items, specF
};
if ('legs' in items || 'hands' in items || 'shoulder' in items) {
return ctx.body = {
success: false,
error: 'To verify it is your own character, please remove your (Shoulders, Hands, and Pants) from your character and try again.'
};
}
ctx.session.foundChar = foundChar; // This line here
console.log(ctx.session);
ctx.body = {
success: true,
charData
};
} catch (err) {
console.log(err);
ctx.status = err.status || 500;
ctx.body = {
message: err.message
};
}
});
When it processes ctx.session.foundChar = foundChar it seems to reset my session for some reason, and logging the session shows {} instead of
{
authenticated: true,
userid: 1
...
}
But if I change ctx.session.foundChar = "Hello"; < Works just fine.
I don't know if there is a data limit or something to the session or what as this wasn't an issue with express-session but I'm trying to convert it all over to Koa, anyways not sure why my session is getting reset.
Example of what foundChar looks like
{ userid: 1,
username: 'Blah',
authenticated: true,
userLevel: 5,
hasMainCharacter: true,
foundChar:
{ lastModified: 1453702285000,
name: 'Blah',
realm: 'Mal\'Ganis',
battlegroup: 'Vindication',
class: 4,
race: 5,
gender: 0,
level: 100,
achievementPoints: 6335,
thumbnail: 'internal-record-3684/9/119507209-avatar.jpg',
calcClass: 'c',
faction: 1,
items:
{ averageItemLevel: 714,
averageItemLevelEquipped: 573,
head: [Object],
neck: [Object],
back: [Object],
chest: [Object],
wrist: [Object],
waist: [Object],
feet: [Object],
finger1: [Object],
finger2: [Object],
trinket1: [Object],
trinket2: [Object],
mainHand: [Object],
offHand: [Object],
level: 100,
class: 4,
thumbnail: 'internal-record-3684/9/119507209-avatar.jpg',
name: 'Blah' },
talents: [ [Object], [Object] ],
totalHonorableKills: 258 } }
So this logs properly, but then after refreshing the page im no longer authenticated and ctx.session is {}
Problem
Your problem is, because of koajs/session usage which is
Simple cookie-based session middleware for Koa.
Which means when ctx.session is being serialized into json and stored in cookie after each request and is being deserialized before each request.
Unfortunately cookie has limited size and when you try to store big object into it with ctx.session.foundChar = foundChar it exceeds maximum cookie size and results currupted session cookie.
For same reason ctx.session.foundChar = "Hello" works, because json size does not exceed max cookie size.
Solution
Use db based storage for session, good choice for it could be koa-session-storage.
Look session storage layer for configuration options
The store configuration option specifies where the session data is
stored. If omitted or set to "cookie" then session data will be
stored in the cookie itself.
If you wish to store session data elsewhere (e.g. in Mongo, Redis,
etc.) then you must set this to an object which exposes the following
API:
load(sid) - load session data for given session id * sid -
{String} session identifier. * returns a Promise, Thunk or generator which returns a JSON string of the session object data.
save(sid, data) - save session data for given session id *
sid - {String} session identifier. * data - _{String} session
data converted to JSON string. * returns a Promise, Thunk or
generator which returns once data is saved.
remove(sid) - remove session data for given session id *
sid - {String} session identifier. * returns a Promise, Thunk
or generator which returns once removal is complete.
The following storage layers are currently available:
MongoDB -
koa-session-mongo