Няколко въпроса и проблема за NodeJs

uphero

Registered
Занимавам се тия дни с nodejs и еxpressjs.
Но нещо не ми се получава, и въобще не ми харесва кода който генерирам (дано грешката е в мен).

Първо тия mysql заявки връщат абсурдни глупости и виждате какви гимнастики се правят за да се вземе резултата. Ползвам пакета mysql2.
Второ изведнъж спря да ми работи кода в loop-а където се мъча да обработя фийда, feed_map е JSON където съм задал кое поле от фийда къде да бъде добавено.
key променливата вместо да е различна за всеки item връща
Код:
--------------------------------
guid
guid
guid
guid
guid
guid
guid
guid
guid
guid
guid
guid
--------------------------------
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
isoDate
--------------------------------
GET /cron/fetch-rss 201 260.399 ms - 2

JavaScript:
    async fetchLast() {
      
        let sql = `SELECT t1.rss_url as url, t2.feed_map as map, t1.id as ID FROM rss_feeds as t1 LEFT JOIN rss_map as t2 ON t1.id = t2.rss_id WHERE t1.status = 1 ORDER BY t1.last_fetch ASC LIMIT 1`;
        let [row, _] = await db.query(sql);
        let rss_url = row[0].url;
        let feed_map = JSON.parse(row[0].map);
        let rss_id = row[0].ID;
        var last_fetch = this.formatDate(new Date());
        let sqlUpdate = `UPDATE rss_feeds SET last_fetch = '${last_fetch}' WHERE id = ${rss_id}`;
        await db.query(sqlUpdate);
 
        let parser = new Parser();
        let feed = await parser.parseURL(rss_url);
        feed.items.forEach(item => {
            var news = {
                news_title: '',
                news_content: '',
                date_created: '',
                news_image: '',
                news_url: ''
            };
           
            Object.keys(item).forEach(key => {
                for(var j in feed_map) {
                    console.log(key);
                    if(key == feed_map[j].key) {
                        news[feed_map[j].type.toString()] = (key == 'enclosure') ? item[key].url.toString() : item[key].toString();
                    }
                }
                console.log('--------------------------------');
            });
            this.storeNews(news);
        });
    }
 
Последно редактирано:
Голяма каша е кода (или по-скоро изглежда каша понеже лиспват примери със структурата на JSON-а, който имаш и обекта, който се опитваш да направиш) и е трудно да се разбере какво трябва да се получи.

Иначе от къде идва този k

Код:
(k == 'enclosure')
 
Пробвам да обработя този фийд - https://darik.bg/rss
feed_map това долу, като ако key е empty го пропускаме, не ни трябва.
Иначе това
(k == 'enclosure')
е останало от едни опити за дебъг реално е key. Ще едитна поста да се разбира.
Код:
[
  {
    "type": "creator",
    "key": "empty"
  },
  {
    "type": "title",
    "key": "news_title"
  },
  {
    "type": "link",
    "key": "empty"
  },
  {
    "type": "pubDate",
    "key": "empty"
  },
  {
    "type": "author",
    "key": "empty"
  },
  {
    "type": "content:encoded",
    "key": "news_content"
  },
  {
    "type": "content:encodedSnippet",
    "key": "empty"
  },
  {
    "type": "enclosure",
    "key": "news_image"
  },
  {
    "type": "content",
    "key": "empty"
  },
  {
    "type": "contentSnippet",
    "key": "empty"
  },
  {
    "type": "guid",
    "key": "news_url"
  },
  {
    "type": "isoDate",
    "key": "date_created"
  }
]
 
Ами key ще ти се промени, когато дойде ред на външния цикъл да извърти. За всеки key ти реално въртиш feed_map. Съответно същата стойност ще я виждаш толкова пъти, колкото стойности имаш в масива feed_map.

Аз бих опростил feed_map, ако е сигурно, че типовете(type) вътре са уникални. Примерно:
JSON:
{
    "creator": "empty",
    "title": "news_title",
    "link": "empty",
    // и т.н.
}

По този начин ще имаш директен достъп използвайки името на филда - feed_map[key]. Ако е възможно да имаш повтарящи типове в масива, то тогава това няма да сработи (не виждам логика да има повтарящи се типове, но да речем, че може), то тогава може да ползваш малко по-опростен вариант за намиране на елемент от feed_map

JavaScript:
Object.keys(item).forEach(key => {
    var feed = feed_map.find(i => i.type === key);

    // ако key е "empty" най-вероятно не искаме да правим нищо
    if (feed.key === "empty") continue;

    // тука ти използваш type но май си имал предвид key
    news[feed.key] = (key == 'enclosure') ? item[key].url.toString() : item[key].toString();
    console.log('--------------------------------');
});

Нещо такова би трябвало да стане.

А, ако опростиш JSON-а, то тогава вместо

JavaScript:
var feed = feed_map.find(i => i.type === key);
ще стане
JavaScript:
var feed = feed_map[key];

което е доста по-ефикасно.
 
Нормализирах си json-a и с твоя код вече работи правилно.
Код:
Object.keys(item).forEach(key => {
                var feed = feed_map[key];
            
                if (feed === "empty")  {
                    return;
                }

                news[feed] = (key == 'enclosure') ? item[key].url.toString() : item[key].toString();
            });
 
Ако визираш библиотека, то не мога да помогна. Аз съм PHP и .NET-аджия. Не съм писал приложения на NodeJS от 100г. Даже библиотеката, която си избрал не съм я чувал.

Изглежда достатъчно опростено. Зависи колко е голям проекта, може да ти е по-добре с някой ORM. С обекти се работи по-лесно, но ORM-а си идва с негови недостатъци и за прости проекти не си заслужава. Винаги можеш ръчно да си създадеш DTO-та, за да си направиш сам кода по-четим, но по това, което си дал, така представено, не изглежда зле.

Малко логически не ми харесва кода. Ъпдейтваш last_fetch колоната преди да си се подсигурил, че успешно си парснал фийда.

Бих сложил един промис да ъпдейтна базата данни, само ако съм приключил парсването успешно, иначе бих желал да пробвам отново този фийд или да го маркирам като счупен, за да не се опитвам повече.

Също бих отделил малко повече време за именуване на нещата. Примерно в news обекта бих махнал префикса news_. Така или иначе обекта ти вече се казва news и няма смисъл да пишеш news.news_title. По-четимо е news.title.

П.П. След последния ти коментар
Това var feed го преименувай примерно на var fieldValue понеже вече не връщаш цял feed обект, а само стойност на полето. И "empty" най-вероятно ще е най-добре да го замениш директно с null. Няма смисъл да имаш стойност "empty" освен, ако няма специално значение.

Също return-а в цикъла ти ще прекъсне целия цикъл и в някои случаи ще имаш непълен news обект. Най-вероятно искаш да продължиш с останалите, за това използвах continue в моя пример.

П.П. Между другото, вместо var ползвай let за деклариране на променливи. А където е възможно винаги предпочитай const пред let.
 
Еби му и смотания js, с питон по добре стана.
Да се има предвид че сефте го пипам.

Python:
    for item in feed.entries:
        data = {"title": '', "content": '', "date_created": '', "image": '', "category": '', "cat_name": '', "url": ''}
        for key in item:  
            if key == 'links': # link & image
                for link in item[key]:
                    link_key = "image" if "image" in link['type'] else "link"
                    data[link_key] = link['href']
            else: # all other data
                if rss_map[key] == 'empty':
                    continue
                if rss_map[key] == 'content':
                    data[rss_map[key]] = item[key][0]['value']
                else:
                    data[rss_map[key]] = item[key]
        store_news(data)
        print('------------------------------')

Python:
import feedparser
import ssl
import json
import mysql.connector
import datetime
import dateparser 
import os
import requests
from PIL import Image
 
if hasattr(ssl, '_create_unverified_context'):
    ssl._create_default_https_context = ssl._create_unverified_context
    
db = mysql.connector.connect(
  host = "69.18.14.19",
  database = "rss_news",
  user = "rss_news",
  password = "kji07809)(*&*"
)
cursor = db.cursor()
cur = db.cursor(dictionary=True)
def resize_image(image):
    image_path = 'Python/rss/images/'
    # download image
    thumb = os.path.basename(image)
    r = requests.get(image, allow_redirects=True) 
    open(f"{image_path}/{thumb}", 'wb').write(r.content)
    # create thumb
    im = Image.open(f"{image_path}/{thumb}")
    thumb_im = im.resize((400, 400))
    thumb_im.save(f"{image_path}/thumb/{thumb}")
 
def store_news(data):  
    data["date_created"] = dateparser.parse(data["date_created"])
    sql_insert = "INSERT INTO news (title, content, date_created, category, image, url, cat_name) VALUES (%s, %s, %s, %s, %s, %s, %s)"
    val = (data["title"], data["content"], data["date_created"], data["category"], data["image"], data["url"], data["cat_name"])
    cur.execute(sql_insert, val)
    db.commit()
    if data["image"] != 'placeholder.jpeg':
        try:
            resize_image(data["image"])
        except:
            print('error store image')

cur.execute("SELECT t1.rss_url as url, t2.feed_map as map, t1.id as ID FROM rss_feeds as t1 LEFT JOIN rss_map as t2 ON t1.id = t2.rss_id WHERE t1.status = 1 ORDER BY t1.last_fetch ASC LIMIT 1")
row = cur.fetchone()
rss_url = row['url']
feed_map = row['map']
rss_map = json.loads(feed_map)
rss_id = row['ID']
date_time = datetime.datetime.now()
try:
    feed = feedparser.parse(rss_url)
    for item in feed.entries:
        data = {"title": '', "content": '', "date_created": '', "image": '', "category": '', "cat_name": '', "url": ''}
        for key in item:   
            if key == 'links': # link & image
                for link in item[key]:
                    link_key = "image" if "image" in link['type'] else "link"
                    data[link_key] = link['href']
            else: # all other data 
                if rss_map[key] == 'empty':
                    continue
                if rss_map[key] == 'content':
                    data[rss_map[key]] = item[key][0]['value']
                else:
                    data[rss_map[key]] = item[key]
        store_news(data) 
        print('------------------------------')
    # timestamp update rss table
    try:
        sql_update_rss = """UPDATE rss_feeds SET last_fetch = %s WHERE id = %s"""
        sql_input = (date_time, rss_id)
        cur.execute(sql_update_rss, sql_input)
        db.commit()
        print('sql update ok', rss_id)
    except:
        print('sql update write log')
except:
    # feed not readable, write log
    print('error read feed')
 

Back
Горе