In my app, users create posts and I'd like to show trending posts by the number of views, comments, etc in a specific date range. To do that I thought I can create a custom event as below:
await FirebaseAnalytics.instance.logEvent(
name: "trending_contents",
parameters: {
"content_type": EnumToString.convertToString(type),
"content_id": contentModel.externalId,
"action_type": "post",
"point": 3,
},
);
I wonder if it is possible to use Google Analytics Data API to get trending posts by a specific date range? Or is there any better way to get trending posts instead of google analytics data API?
I finally found a solution on how to use Google Analytics Data API to manage trending content. If anyone is looking for a solution for a similar need, here is what I've done so far:
I send a custom event in specific situations such as when the user views the content etc. as below. If you use parameters' names according to predefined dimensions & metrics (see API Dimensions & Metrics), it will be easy to prepare a custom report (at least it was for me...). Later, I use contentType and contentId as dimensions and eventValue as a metric in the custom report.
await FirebaseAnalytics.instance.logEvent(
name: "trending_contents",
parameters: {
"content_type": EnumToString.convertToString(event.type),
"content_id": contentId,
"action_type": "view",
"value": 1,
},
);
Lastly, I created a scheduled cloud function that runs every 6 hours and populates firebase collection according to custom report results. This report gives contentIds in a specific date range ordered by the sum of values that I sent in a custom event
P.S. you need to create a service account in Google Cloud Console, then generate JSON credentials for it and add the file to your project (see credentialsJsonPath variable below). Then you need to add its email address to google analytics 'Property Access Management' section to access analytics data. To see Google Analytics Data API samples, you can check their GitHub repo
const { BetaAnalyticsDataClient } = require('#google-analytics/data');
exports.scheduledTrendingFunction = functions.pubsub.schedule('0 */6 * * *').onRun((context) => {
const propertyId = process.env.GA_PROPERTY_ID;
const credentialsJsonPath = process.env.GA_CRENDENTIALS_PATH;
const analyticsDataClient = new BetaAnalyticsDataClient({
keyFilename: credentialsJsonPath,
});
async function runReport(filterType) {
// [START analyticsdata_json_credentials_run_report]
const [response] = await analyticsDataClient.runReport({
property: `properties/${propertyId}`,
dateRanges: [
{
startDate: '3daysAgo',
endDate: 'today',
},
],
dimensions: [
{
name: 'contentType',
},
{
name: 'contentId'
}
],
metrics: [
{
name: 'eventValue'
},
],
dimensionFilter: {
andGroup: {
expressions: [
{
filter: {
fieldName: "eventName",
inListFilter: {
values: ["trending_contents"]
}
}
},
{
filter: {
fieldName: "contentType",
inListFilter: {
values: [filterType]
}
}
}
]
}
},
offset: 0,
limit: 20,
orderBys: [
{
desc: true,
metric: {
metricName: "eventValue"
}
}
]
});
// [END analyticsdata_json_credentials_run_report]
const batch = admin.firestore().batch();
// BATCH: delete
const trendRef = admin.firestore().collection('trends').doc(filterType);
batch.delete(trendRef);
const subTrendRef = admin.firestore().collection('trends').doc(filterType).collection('trendContents');
// console.log(response);
response.rows.forEach((row, index) => {
// BATCH: add each contentId to trend
const contentId = row['dimensionValues']['1']['value'];
batch.set(subTrendRef.doc(contentId), {priority: index + 1});
});
// Commit the batch
await batch.commit();
}
runReport("book");
return null;
});
Related
I have a node app that I am running locally in a lamda function using netlify dev. I get a 500 response error, not sure why I am pretty certain I have all the right credentials. I don't know how else to debug this. Hope some one can help I read something about trying to send the response 3s then 6s so on but that still returned the exact same issue. This is my first time using the api so not exactly sure what to do.
Keep in mind I am using the developer playground as my oauth redirect and have generated a refresh token there
const { google } = require("googleapis")
const { oAuth2 } = google.auth
const oAuth2Client = new oAuth2(
"fdsfs.apps.googleusercontent.com",
"fdsaf"
)
oAuth2Client.setCredentials({
refresh_token:
"1//0fdsfas",
})
// Create a new calender instance.
const calendar = google.calendar({ version: "v3", auth: oAuth2Client })
// Create a new event start date instance for temp uses in our calendar.
const eventStartTime = new Date()
eventStartTime.setDate(eventStartTime.getDay() + 2)
// Create a new event end date instance for temp uses in our calendar.
const eventEndTime = new Date()
eventEndTime.setDate(eventEndTime.getDay() + 4)
eventEndTime.setMinutes(eventEndTime.getMinutes() + 45)
// Create a dummy event for temp uses in our calendar
const event = {
summary: `Meeting with David`,
location: `3595 California St, San Francisco, CA 94118`,
description: `Meet with David to talk about the new client project and how to integrate the calendar for booking.`,
colorId: 1,
start: {
dateTime: eventStartTime,
timeZone: "America/Denver",
},
end: {
dateTime: eventEndTime,
timeZone: "America/Denver",
},
}
// Check if we a busy and have an event on our calendar for the same time.
calendar.freebusy.query(
{
resource: {
timeMin: eventStartTime,
timeMax: eventEndTime,
timeZone: "America/Denver",
items: [{ id: "primary" }],
},
},
(err, res) => {
// Check for errors in our query and log them if they exist.
if (err) return console.error("Free Busy Query Error: ", err)
// Create an array of all events on our calendar during that time.
const eventArr = res.data.calendars.primary.busy
// Check if event array is empty which means we are not busy
if (eventArr.length === 0)
// If we are not busy create a new calendar event.
return calendar.events.insert(
{ calendarId: "primary", resource: event },
err => {
// Check for errors and log them if they exist.
if (err)
return console.error("Error Creating Calender Event:", err)
// Else log that the event was created.
return console.log("Calendar event successfully created.")
}
)
// If event array is not empty log that we are busy.
return console.log(`Sorry I'm busy...`)
}
)
It was a simple mistake
const { OAuth2 } = google.auth with capital O !not oAuth2
I am trying to use the gridsome-plugin-firestore plugin (https://gridsome.org/plugins/gridsome-source-firestore). I want to use that plugin to connect to a simple firestore database collection called news. News has a number of documents with various fields:
content
published_date
summary
author
title
etc.
Does anyone know how am I supposed to set up the gridsome.config file to access this collection using the gridsome-plugin-firestore plugin?. I cannot figure it out from the instructions given.
The Gridsome docs are a little clearer than npm version, but you need to generate a Firebase Admin SDK private key and download the whole file to your Gridsome app and import it into gridsome.config.js as a module, name it whatever you want for the options > credentials: require field as below.
First, you'll need the Firestore plugin
$ yarn add gridsome-source-firestore
Then in gridsome.config.js
const { db } = require('gridsome-source-firestore')
module.exports = {
plugins: [
{
use: 'gridsome-source-firestore',
options: {
credentials: require('./my-project-firebase-adminsdk-qw2123.json'), //
Replace with your credentials file you downloaded.
debug: true, // Default false, should be true to enable live data updates
ignoreImages: false, // Default false
imageDirectory: 'fg_images', // Default /fg_images
collections: [
{
ref: (db) => {
return db.collection('news')
},
slug: (doc, slugify) => {
return `/news/${slugify(doc.data.title)}`
},
children: [
{
ref: (db, parentDoc) => {
return parentDoc.ref.collection('posts')
},
slug: (doc, slugify) => {
return `/${slugify(doc.data.title)}`
},
}
]
}
]
}
}
]
}
You might have to change "posts" to "content" depending on your DB structure and alter the corresponding page queries to suit, there are some examples and other useful setup info in this Gridsome Firestore starter on Github https://github.com/u12206050/gridsome-firestore-starter.git
First of all I know NOSQL systems do not have JOIN. But I know there is a way for getting a datas with another table values.
About my app:
This app is basic social network app. People can share photos. These posts saving firebase database 'realtime database' not cloud firestore than it has a timeline page. this page shows shared posts. I need to show posts with publisher information.
Users login with firebase authentication and I have users table called kullanici like this.
I have Posts table like this.
I need to delete displayName in Posts table than get isim in kullanici table.
my needed data is: Post with kullanici->{posts.{postid}.userid}->isim.
my working code is below:
return (dispatch) => {
firebase.database().ref(`/posts`).endAt("tarih").limitToLast(2)
.on('value', snapshot => {
dispatch({type: STUDENT_LIST_DATA_SUCCESS, payload: snapshot.val()});
});
};
my returned data is below:
Object {
"-L9tnfvm6jQiKLc378c6": Object {
"aciklama": "",
"baslik": "Ensar mı Ahmet mi",
"displayName": "HasanRiza",
"image": "https://hasan-riza-uzuner.s3.amazonaws.com/1523535677033.png",
"like": 244,
"tarih": 1523535757133,
"userid": "fD7IfKAhXogFwHtfKYiF7LMtXNp1",
},
"-LYHPJgR4sywTzpcxX7A": Object {
"aciklama": "Ev",
"baslik": "Nasıl",
"displayName": "HasanRiza",
"image": "https://hasan-riza-uzuner.s3.us-east-2.amazonaws.com/1549718296409.png",
"like": 1,
"tarih": 1549718342522,
"userid": "fD7IfKAhXogFwHtfKYiF7LMtXNp1",
},
}
var promises = [];
group_ids.forEach(function (group_id) {
promises.push(firebase.firestore().collection('Group').doc(group_id).get())
});
Promise.all(promises).then(function(docs) {
docs.forEach((groupDoc) => {
group.name = groupDoc._data['name'];
group.city = groupDoc._data['city'];
group.state = groupDoc._data['state'];
groups.push(group);
});
console.log(groups);
});
here is the multiple document for offer and each offer cantains bidderId that is referenced to users collection and user id.
I want to fetch offer list contains user collection.
I am using angularfire and here is my code.
this.liveOffers=this.db.collection("offers",ref => ref.where('offerExpired', '==', 0).where('isStart', '==', 1)).snapshotChanges().pipe(
map(actions => actions.map(a => {
const data={} = a.payload.doc.data() as offer;
const id = a.payload.doc.id;
var bidder=this.db.doc(data.bidderId).snapshotChanges().subscribe(key=>{
console.log(key.payload.data());
});
return { id, ...data,bidder };
})) );
Here console.log(key.payload.data()); is logging the data for user but it can not bind with bidder variable and i can not use the user object in front end.
Please let me know how can I fetch the offer record with user details.
You need to use a combination of switchMap and combineLatest to get it done.
This is a pseudo-code approach
const temp = []
this.offers$ = this.db.collection().snapshotChanges().pipe(
map(auctions=>{
//we save all auctions in temp and return just the bidderId
return auctions.map(auction=>{
const data={} = a.payload.doc.data() as offer;
const id = a.payload.doc.id;
temp.push({id, ...data})
return data.bidderId
})
}),
switchMap(bidderIds=>{
// here you'll have all bidderIds and you need to return the array to query
// them to firebase
return combineLatest(bidderIds.map(bidderId=> return this.db.doc(bidderId)))
}),
map(bidders=>{
// here you'll get all bisders you'll have to set the bidder on each temp obj
// you saved previously
})
)
Make sure you import { combineLatest } from 'rxjs/operators' not 'rxjs'
I found a way. It is working. But I think it is bit big and there might be way to optimize it. Also it is node-js server API and not for the web (JS). Again there might be similar solution for the web (JS)
Once you get data from snapshot object there is _path key in the object returned by data which again have segments which is array and contain collection and ID
const gg = await firestore.collection('scrape').doc('x6F4nctCD').get();
console.log(JSON.stringify(gg.data(), null, 4));
console.log(gg.data().r._path.segments[0]);
console.log(gg.data().r._path.segments[1]);
const gg2 = await firestore
.collection(gg.data().r._path.segments[0])
.doc(gg.data().r._path.segments[1])
.get();
console.log(gg2.data());
{
"fv": {
"_seconds": 1578489994,
"_nanoseconds": 497000000
},
"tsnowpo": 1578489992,
"createdAt": {
"_seconds": 1578489992,
"_nanoseconds": 328000000
},
"r": {
"_firestore": {
"_settings": {
"libName": "gccl",
"libVersion": "3.1.0",
"servicePath": "firestore.googleapis.com",
"port": 443,
"clientConfig": {},
"scopes": [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/datastore"
]
},
"_settingsFrozen": true,
"_serializer": {},
"_projectId": "sss",
"_lastSuccessfulRequest": 1578511337407,
"_preferTransactions": false,
"_clientPool": {
"concurrentOperationLimit": 100,
"activeClients": {},
"terminated": false
}
},
"_path": {
"segments": [
"egpo",
"TJTHMkxOx1C"
]
}
}
}
egpo
TJTHMkxOx1C
{ name: 'Homeware' }
I am having trouble sorting out the new MailChimp API (V3.0). It does not seem like there is a way to call a subscribe method. It seems like I have to use their Sign Up Form. Am I correct?
If by "subscribe" you mean that your application will add someone to a mailing list, you may want to take a look at the List Members Collection portion of their documentation.
http://kb.mailchimp.com/api/resources/lists/members/lists-members-collection
Adding/editing a subscriber via MailChimp v3.0 REST API.
// node/javascript specific, but pretty basic PUT request to MailChimp API endpoint
// dependencies (npm)
var request = require('request'),
url = require('url'),
crypto = require('crypto');
// variables
var datacenter = "yourMailChimpDatacenter", // something like 'us11' (after '-' in api key)
listId = "yourMailChimpListId",
email = "subscriberEmailAddress",
apiKey = "yourMailChimpApiKey";
// mailchimp options
var options = {
url: url.parse('https://'+datacenter+'.api.mailchimp.com/3.0/lists/'+listId+'/members/'+crypto.createHash('md5').update(email).digest('hex')),
headers: {
'Authorization': 'authId '+apiKey // any string works for auth id
},
json: true,
body: {
email_address: email,
status_if_new: 'pending', // pending if new subscriber -> sends 'confirm your subscription' email
status: 'subscribed',
merge_fields: {
FNAME: "subscriberFirstName",
LNAME: "subscriberLastName"
},
interests: {
MailChimpListGroupId: true // if you're using groups within your list
}
}
};
// perform update
request.put(options, function(err, response, body) {
if (err) {
// handle error
} else {
console.log('subscriber added to mailchimp list');
}
});