farmController.js (3625B)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | const { randomUUID: uuidv4 } = require('crypto'); // ✅ Use built-in Node module const { client, COLLECTION_NAME } = require('../config/db'); // --- LOGIC: Create New Memory --- const addMemory = async (req, res) => { try { const { timestamp, sensors, metadata, crop_id, sequence_number, action_taken, outcome } = req.body; // Mock Vector (Replace with real embedding model in production) const vector = Array.from({ length: 4 }, () => Math.random()); const payload = { timestamp: timestamp || new Date().toISOString(), sensors, ...metadata, crop_id: crop_id || "UNKNOWN_CROP", sequence_number: sequence_number || 1, action_taken: action_taken || "PENDING_ACTION", outcome: outcome || "PENDING_OBSERVATION" }; const pointId = uuidv4(); await client.upsert(COLLECTION_NAME, { points: [{ id: pointId, vector: vector, payload: payload }] }); res.json({ success: true, id: pointId, message: "Memory stored successfully" }); } catch (e) { console.error(e); res.status(500).json({ error: e.message }); } }; // --- LOGIC: Dashboard (Unique crops + Latest State) --- const getDashboard = async (req, res) => { try { const latestCropsMap = new Map(); let nextOffset = null; let keepFetching = true; // Scroll through all data while (keepFetching) { const result = await client.scroll(COLLECTION_NAME, { limit: 100, with_payload: true, with_vector: false, // Save bandwidth offset: nextOffset, }); // "Group By" Logic in JavaScript for (const point of result.points) { const p = point.payload; const cropId = p.crop_id; const seq = p.sequence_number || 0; // Check if we have this crop, or if this point is "newer" (higher sequence) if (!latestCropsMap.has(cropId)) { latestCropsMap.set(cropId, point); } else { const currentMax = latestCropsMap.get(cropId).payload.sequence_number || 0; if (seq > currentMax) { latestCropsMap.set(cropId, point); } } } nextOffset = result.next_page_offset; if (!nextOffset) keepFetching = false; } const data = Array.from(latestCropsMap.values()); res.json(data); } catch (e) { res.status(500).json({ error: e.message+"adfasdfads" }); } }; // --- LOGIC: Get History for One Crop --- const getCropHistory = async (req, res) => { try { const { cropId } = req.params; // This filter is fast because we added the Index in db.js const result = await client.scroll(COLLECTION_NAME, { filter: { must: [{ key: "crop_id", match: { value: cropId } }] }, limit: 1000, with_payload: true, with_vector: false }); // Sort Descending by Sequence Number const sorted = result.points.sort((a, b) => (b.payload.sequence_number || 0) - (a.payload.sequence_number || 0) ); res.json(sorted); } catch (e) { res.status(500).json({ error: e.message }); } }; module.exports = { addMemory, getDashboard, getCropHistory }; |