I have the following Mongo Schema which has an array of objects inside of 'balance':
const SubmitDebtSchema = new Schema ({
balance: [{
balanceDate: Date,
newBalance: Number
}],
});
An example console.log of said Schema would then be like this:
balance: Array [
{
id: "20304929403048fd636",
balanceDate: "2020-11-23T10:57:58.845Z",
newBalance: 300
},
{
id:"20fhdjfjwjh39g9395",
balanceDate: "2020-11-23T11:54.58.845Z",
newBalance: 200
} ]
I then have an Axios call which sets an array state like follows:
componentDidMount() {
axios.get("/api/fetch/fetchDebtCards")
.then((response) => {
this.setState({
debts: response.data
})
console.log(this.state.debts)
})
}
Finally, I have the following function which I'm attempting to use to render the results on my web page.
const fetchDebts = this.state.debts.map (debt => {
return (
<IndividualDebtCard key={debt._id}
balance={debt.balance[debt.balance.length - 1][2]}
/>
)
})
This maps through my database, and is attempting to pull the last balance entry to render as props on my web page.
From this last balance entry, I then want to pull the newBalance figure to render in my webpage. So in this example, balance would equal 200.
However, the array.length isn't working. I can't seem to access the last newBalance in my array.
I have simplified my call as it also pulls other entry details, but for simplicity's sake I have removed them. The rest of the call works fine! So it's not a problem with anything else, just getting the last value in the array.
Can anyone point out what I'm doing wrong here?
I think the error is happening because you are using array of objects and trying to get the second index from balance object. For example balance[1][2] is undefined because you can't access objects by index. You can only access objects by key. You can try using balance[1].newBalance if that solves it.
const fetchDebts = this.state.debts.map (debt => {
return (
<IndividualDebtCard key={debt._id}
balance={debt.balance[debt.balance.length - 1].newBalance}
/>
)
})
Related
Currently I store some data in FaunaDB every week. This is done using a cronjob. In my code I'm trying to fetch the documents from only the last two weeks. I'd like to use the timestamp to do so.
One of the documents to fetch:
{
"ref": Ref(Collection("weeklyContributors"), "350395411XXXXXXXX"),
"ts": 1670421954340000,
"data": {
...allMyDataFields
}
}
My code
const now = Date.now() * 1000;
const twoWeeksAgo = (Date.now() - 12096e5) * 1000;
console.log(now); //returns 1670493608804000
console.log(twoWeeksAgo); // returns 1669284008804000
// the stored document has a timestamp of 1670421954340000, so this should be in between [now] and [twoWeeksAgo]
await client.query(
q.Paginate(
q.Range(
q.Match(q.Index("get_weekly_list_by_ts")),
twoWeeksAgo,
now
)
)
);
This is a screenshot of the index I created in Fauna
Above code should fetch all documents where the timestamp's between now and twoWeeksAgo but it returns an empty array (so no documents match the query). Above code doesn't generate any errors, it does return a statuscode 200, so syntax should be fine. Why can't I fetch the document I gave in this example?
UPDATE
Found the solution for the index. The index should filter on Values, not Terms. Enter TS and Ref returns the document. BUt now I don't know how to get the corresponding document.
This returns an error
await client.query(
q.Map(
q.Paginate(
q.Range(
q.Match(q.Index("get_weekly_list_by_ts")),
twoWeeksAgo,
now
)
),
q.Lambda((x) => q.Get(x))
)
);
Changed index screenshot here
Congratulations on figuring out most of the answer for yourself!
As you deduced, the terms definition in an index specifies the fields to search for, and the values definition specifies the field values to return for matching entries.
Since you added the document reference to the values definition, all that you need now is to fetch that document. To do that, you need to Map over the results.
The following example uses Shell syntax, and involves sample documents that I created with a createdAt field recording the creation timestamp (since ts is the last-modified timestamp):
> Map(
Paginate(
Range(
Match(Index("get_weekly_list_by_ts")),
TimeSubtract(Now(), 14, "days"),
Now()
)
),
Lambda(
["ts", "ref"],
Get(Var("ref"))
)
)
{
data: [
{
ref: Ref(Collection("weeklyContributors"), "350498857823502848"),
ts: 1670520608640000,
data: { createdAt: Time("2022-12-01T17:30:08.633Z"), name: 'Fourth' }
},
{
ref: Ref(Collection("weeklyContributors"), "350498864657072640"),
ts: 1670520615160000,
data: { createdAt: Time("2022-12-07T17:30:15.152Z"), name: 'Fifth' }
}
]
}
Since your index returns ts and ref, notice that the Lambda function accepts both parameters in an array. The Lambda parameters have to match the number returned by the index. Then the Lambda calls Get to fetch the document.
In case you're wondering, here's the index definition that I used for my example:
> Get(Index("get_weekly_list_by_ts"))
{
ref: Index("get_weekly_list_by_ts"),
ts: 1670520331720000,
active: true,
serialized: true,
name: 'get_weekly_list_by_ts',
source: Collection("weeklyContributors"),
values: [ { field: [ 'data', 'createdAt' ] }, { field: [ 'ref' ] } ],
partitions: 8
}
My index is misnamed: I used the same name from your original query to help you correlate what is being used.
Note: there is no need to mask the document ID in a document that you share. It is only valid for the database containing the document.
lets say I have post Model and schema contains UserId , Title, Desc and likes array which takes userId's as ref
when I make a query I get a virtual property like this to find out num of like of a post would have
schema.virtual("numLikes").get(function () {
return this.likes.length;
});
But the problem is when I run the findById() Method I dont want to get likes from database because likes array would contain large list of users
const post = await Post.findById(postId).select("-likes -shares");
so how do I get Likes count without fetching likes array ?
I believe this can be done using aggregation, by using the $size operators in a projection:
const aggregate = Post.aggregate([
{ $match: {_id: postId}},
{ $project: {
numberOfLikes: { $size: "$likes" }
}
}
]);
https://docs.mongodb.com/manual/reference/operator/aggregation/size/
https://mongoosejs.com/docs/api/aggregate.html#aggregate_Aggregate-project
This is my problem : I have a document ( let's call it root) containing an array of another documents (stick), that contain another array of another documents (leaf).
Or simply said : root{ stickChain[leaveschain1[ leaf1, leaf2],leaveschain2[ leaf1, leaf2] ]}
I have access to root _id, stick _id, or whatever it is needed to identify each document.
Basically, the best result I've come so far is, when creating my leaves documents, is to store then at the same level tha sticks, or in another word I've come to create an array of leaves in root.
I'm working in javascript and using mongoose
This is the line I've used:
db.collection('root').findOneAndUpdate({ _id: root.id, "stick._id":expTemp._id },{stickChain:{$push: {"leavechain.$": leaf}}})
And I this gives me this result : root{ leavesChain[leaf1,leaf2], stickchain[1,2,3] }
I've come across something new to me (since Mongodb 3.6 there is a new way of handling array of arrays), here is what I've tried :
try{ db.collection('root').findOneAndUpdate(
{ _id: root.id, "stick._id":expTemp._id },
{$push: {"stickChain.$[xpc].leavesChain.$[qac]": leaf}},
{ arrayFilters: [ { "xpc._id": user._id } , { "qac._id": expTemp._id } ]})}
UPDATE
try{ db.collection('root').findAndModify(
{$push: {"root.$[cv].stickChain.$[xpc].leavesChain.$[qac]": leaf}},
{ arrayFilters: [ {"cv._id":user.cv} ,{ "xpc._id": user._id } , { "qac._id": expTemp._id } ],
upsert:true})
.catch(error => console.error(error))
}catch{}
And this gives me a new kind of error : MongoError: Either an update or remove=true must be specified
The thing is that I'm not familiar with how to do it, while I know what I want to do: I want to insert a "leaf" into a specific array in a document fetched in MongoDB. Maybe not the best practice, so any hint are welcome :)
I've splitted my dument like this :
root[stickChain _id]
stick[leavesChain[leaf]]
Thanks to Andrey Popov for his explications
I'm currently trying to get the child data without the key in an array so I can add that to my redux state.
ref.orderByChild(`userId`).equalTo(googleUserInfo[0].userId).once('value', streamSnapshot => {
if (streamSnapshot.exists()) {
googleUserInfo[0] = (streamSnapshot.val())
}
Currently this returns
[{…}]0: {-LbJneodI2SaUglB6fwx: {…}}length: 1__proto__: Array(0)
But I would like this
[{…}]
0:
{
displayName: "Seth Jones"
userAvi: "https://lh6.googleusercontent.com/-RABcz3kK1ew/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3rfzHCLV9A7LfiGWKtTOuq5rJmtQpg/s96-c/photo.jpg"
userEmail: "xxxx#gmail.com"
userFirstName: "Seth"
userId: "103977654052015523435"
userLastName: "Jones"
}
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
You need to loop over the results, to get to the individual values:
ref.orderByChild('userId').equalTo(googleUserInfo[0].userId).once('value', streamSnapshot => {
streamSnapshot.forEach((child) => {
googleUserInfo[0] = (child.val())
});
What I am trying to do
I am creating a social media app with react native and firebase. I am trying to call a function, and have that function return a list of posts from off of my server.
Problem
Using the return method on a firebase query gives me a hard to use object array:
Array [
Object {
"-L2mDBZ6gqY6ANJD6rg1": Object {
//...
},
},
]
I don't like how there is an object inside of an object, and the whole thing is very hard to work with. I created a list inside my app and named it items, and when pushing all of the values to that, I got a much easier to work with object:
Array [
Object {
//...
"key": "-L2mDBZ6gqY6ANJD6rg1",
},
]
This object is also a lot nicer to use because the key is not the name of the object, but inside of it.
I would just return the array I made, but that returns as undefined.
My question
In a function, how can I return an array I created using a firebase query? (to get the objects of an array)
My Code
runQ(group){
var items = [];
//I am returning the entire firebase query...
return firebase.database().ref('posts/'+group).orderByKey().once ('value', (snap) => {
snap.forEach ( (child) => {
items.push({
//post contents
});
});
console.log(items)
//... but all I want to return is the items array. This returns undefined though.
})
}
Please let me know if I'm getting your question correctly. So, the posts table in database looks like this right now:
And you want to return these posts in this manner:
[
{
"key": "-L1ELDwqJqm17iBI4UZu",
"message": "post 1"
},
{
"key": "-L1ELOuuf9hOdydnI3HU",
"message": "post 2"
},
{
"key": "-L1ELqFi7X9lm6ssOd5d",
"message": "post 3"
},
{
"key": "-L1EMH-Co64-RAQ1-AvU",
"message": "post 4"
}
...
]
Is this correct? If so, here's what you're suppose to do:
var items = [];
firebase.database().ref('posts').orderByKey().once('value', (snapshot) => {
snapshot.forEach((child) => {
// 'key' might not be a part of the post, if you do want to
// include the key as well, then use this code instead
//
// const post = child.val();
// const key = child.key;
// items.push({ ...post, key });
//
// Otherwise, the following line is enough
items.push(child.val());
});
// Then, do something with the 'items' array here
})
.catch(() => { });
Off the topics here: I see that you're using firebase.database().... to fetch posts from the database, are you using cloud functions or you're fetching those posts in your App, using users' devices to do so? If it's the latter, you probably would rather use cloud functions and pagination to fetch posts, mainly because of 2 reasons:
There might be too many posts to fetch at one time
This causes security issues, because you're allowing every device to connect to your database (you'd have to come up with real good security rules to keep your database safe)