llamaindex 向量化VectorStoreIndex

1.使用VectorStoreIndex简单实用:VectorStoreIndex.from_documents(documents)读取文档。Documents

2.使用读取切分好的节点(常用)VectorStoreIndex(nodes) 切分好的节点。

不常用:查询query_engine=index.as_query_engine(similarity_top=3) 查询 query_engine.query("xxxxxx?") 即可


chroma设置

首先需要导入

import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore


from llama_index.core import SimpleDirectoryReader,VectorStoreIndex,Settings,StorageContext,load_index_from_storage

创建chroma存储目录以及集合名词

# chroma初始化 存储目录
chroma_client=chromadb.PersistentClient(path="./storage/chroma")
#chroma的向量集合
chroma_context=chroma_client.get_or_create_collection("My_collection")

使用llama_index加入刚刚创建的db 中的合集转为chromavectorstore对象并最终转为Storage对象用于处理

# 使用llama_index 来使用chroma库 导入建刚刚创建的chroma集合 导入向量库
vector_store=ChromaVectorStore(chroma_collection=chroma_context)
#整合向量存储的方法 用于下面的保存操作 index=VectorStoreIndex(new_nodes,storage_context=storage_context)
storage_context=StorageContext.from_defaults(vector_store=vector_store)

向量化 及关联使用storage对象,最终使用persist方法存储 (persist_dir 其中还存储向量与节点关系数据【Chroma 存向量,persist 存关联】)

index=VectorStoreIndex(new_nodes,storage_context=storage_context)
# 该处负责存储,需要执行后才能存储 且制定了目录。必须使用persist_dir 其中还存储向量与节点关系数据
index.storage_context.persist(persist_dir="./storage")

载入chroma的合集

#并将对象转唯llamaindex到ChromeVectorStore向量对象

loaded_client=chromadb.PersistentClient(path='./storage/chroma')
loaded_collection=loaded_client.get_collection("My_collection")

#载入chroma文件中的collection到向量对象

loaded_vector_store=ChromaVectorStore(chroma_collection=loaded_collection)

# 使用StorageContext 载入转为Storage对象用于载入

loaded_storage_context=StorageContext.from_defaults(

    persist_dir="./storage",

    vector_store=loaded_vector_store

)

#将storage对象转为可用的index,后续用于查询

index=load_index_from_storage(loaded_storage_context)

query_engine=index.as_query_engine(similarity_top_k=3)

ee=query_engine.query("where is Link")

print(ee)

整体DEMO代码

from llama_index.core import SimpleDirectoryReader,VectorStoreIndex,Settings,StorageContext,load_index_from_storage
from llama_index.core.node_parser import SentenceSplitter
from llama_index.retrievers import bm25
# from llama_index.core.retrievers import BM25Retriever
from llama_index.llms.ollama import Ollama
from llama_index.embeddings.ollama import OllamaEmbedding
import jieba
import time
import joblib
import chromadb
from llama_index.vector_stores.chroma import ChromaVectorStore


OLLAMA_URL="http://127.0.0.1:11434"
EMBED_MODEL="qwen3-embedding:0.6b"
LLM_MODEL="qwen3:0.6b"

Settings.embed_model=OllamaEmbedding(
    model_name=EMBED_MODEL,base_url=OLLAMA_URL
)
Settings.llm=Ollama(
    model=LLM_MODEL,base_url=OLLAMA_URL
)

# chroma初始化 存储目录
chroma_client=chromadb.PersistentClient(path="./storage/chroma")
#chroma的向量集合
chroma_context=chroma_client.get_or_create_collection("My_collection")

# 使用llama_index 来使用chroma库 导入建刚刚创建的chroma集合 导入向量库
vector_store=ChromaVectorStore(chroma_collection=chroma_context)
#整合向量存储的方法 用于下面的保存操作 index=VectorStoreIndex(new_nodes,storage_context=storage_context)
storage_context=StorageContext.from_defaults(vector_store=vector_store)

documents=SimpleDirectoryReader("data").load_data()

print(documents)

splitter=SentenceSplitter(chunk_size=512,chunk_overlap=30)

new_nodesx=splitter.get_nodes_from_documents(documents)

print(new_nodesx)

documents=SimpleDirectoryReader(input_files=["add.docx",]).load_data()

print(documents)

documents[0].metadata['MAC']='adgfa-192ga'
documents[0].metadata['document_id']=documents[0].id_

print(documents)
new_nodes=splitter.get_nodes_from_documents(documents)
print(new_nodes)

class ChineseBM25Retriever(bm25.BM25Retriever):
    def _tokenize(self,text):
        return [w for w in jieba.cut(text) if w.strip()]

c=time.time()
retriever=ChineseBM25Retriever(nodes=new_nodes,similarity_top_k=10)
print(time.time()-c,retriever)

# c=time.time()
# retriever=ChineseBM25Retriever(nodes=new_nodesx,similarity_top_k=10)
# print(time.time()-c,retriever)
retriever.persist("./bm25_retriever")


retrieved_nodes = retriever.retrieve(
    "What is link?"
)
for node in retrieved_nodes:
    print(node)


del retriever
retriever = bm25.BM25Retriever.from_persist_dir("./bm25_retriever")

print("Reload BM25 from disk")
retrieved_nodes = retriever.retrieve(
    "What is link?"
)
for node in retrieved_nodes:
    print(node)


index=VectorStoreIndex(new_nodes,storage_context=storage_context)
# 该处负责存储,需要执行后才能存储 且制定了目录。必须
index.storage_context.persist(persist_dir="./storage")

query_engine=index.as_query_engine(similarity_top_k=3)
ee=query_engine.query("where is Link")
print(ee)

print('Load')

#载入chroma文件中的collection到向量对象
loaded_client=chromadb.PersistentClient(path='./storage/chroma')
loaded_collection=loaded_client.get_collection("My_collection")
#并将对象转唯llamaindex到ChromeVectorStore向量对象
loaded_vector_store=ChromaVectorStore(chroma_collection=loaded_collection)

# 使用StoragContext 载入
loaded_storage_context=StorageContext.from_defaults(
    persist_dir="./storage",
    vector_store=loaded_vector_store
)

#转为可用的index
index=load_index_from_storage(loaded_storage_context)
query_engine=index.as_query_engine(similarity_top_k=3)
ee=query_engine.query("where is Link")
print(ee)
发表在 None | 留下评论

Llamaindex BM25 实验

还是得实践和查看官方文档,https://developers.llamaindex.ai/python/examples/retrievers/bm25_retriever/ 之前学习被AI坑了好久全是AI幻觉,下面的是2026-01-07 可以运行代码。(Name: llama-index Version: 0.14.10;Name: llama-index-retrievers-bm25 Version: 0.6.5)
主要坑点BM25的存储 retriever.persist(“./bm25_retriever”)和载入retriever = bm25.BM25Retriever.from_persist_dir(“./bm25_retriever”)
AI老说这个是已经失效了,让我用pickle,但是BM25 实现算法又不能全部pickle下来,后来想到直接用node去直接生成BM25,但是BM25应对中文需要jieba分词,分词效率每秒100万字,且需要启动时间,所以如果500片2000千字的文章转换成的节点至少要2秒左右才能生成BM25 的retriever对象!AI害人不浅,全是幻觉。

from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter
from llama_index.retrievers import bm25
# from llama_index.core.retrievers import BM25Retriever
import jieba
import time
import joblib
documents=SimpleDirectoryReader("data").load_data()

print(documents)

splitter=SentenceSplitter(chunk_size=512,chunk_overlap=30)

new_nodesx=splitter.get_nodes_from_documents(documents)

print(new_nodesx)

documents=SimpleDirectoryReader(input_files=["add.docx",]).load_data()

print(documents)

documents[0].metadata['MAC']='adgfa-192ga'
documents[0].metadata['document_id']=documents[0].id_

print(documents)
new_nodes=splitter.get_nodes_from_documents(documents)
print(new_nodes)

class ChineseBM25Retriever(bm25.BM25Retriever):
    def _tokenize(self,text):
        return [w for w in jieba.cut(text) if w.strip()]

c=time.time()
retriever=ChineseBM25Retriever(nodes=new_nodes,similarity_top_k=10)
print(time.time()-c,retriever)

# c=time.time()
# retriever=ChineseBM25Retriever(nodes=new_nodesx,similarity_top_k=10)
# print(time.time()-c,retriever)
retriever.persist("./bm25_retriever")


retrieved_nodes = retriever.retrieve(
    "What is link?"
)
for node in retrieved_nodes:
    print(node)


del retriever
retriever = bm25.BM25Retriever.from_persist_dir("./bm25_retriever")

print("Reload BM25 from disk")
retrieved_nodes = retriever.retrieve(
    "What is link?"
)
for node in retrieved_nodes:
    print(node)

执行结果:

(base) EgoistdeMacBook-Pro:rag maysrp$ python doc.py
/opt/anaconda3/lib/python3.13/site-packages/jieba/_compat.py:18: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources
2026-01-07 22:47:06,574 - INFO - NumExpr defaulting to 12 threads.
[Document(id_='de9ebe13-a86b-4331-a6aa-8046de5263d1', embedding=None, metadata={'file_name': 'Suzhou.docx', 'file_path': '/Users/maysrp/rag/data/Suzhou.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10159, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='Suzhou is Link’s best city in her live.', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}'), Document(id_='92e769b9-e293-48e2-a5ac-743a753b167a', embedding=None, metadata={'file_name': 'game.docx', 'file_path': '/Users/maysrp/rag/data/game.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10138, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='Link love play Switch game!', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}'), Document(id_='7cc63b7a-19fb-4d27-b58d-266101e2c49f', embedding=None, metadata={'file_name': 'sutdent.docx', 'file_path': '/Users/maysrp/rag/data/sutdent.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10142, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='Link is high school sutdent!', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}'), Document(id_='9d3ee148-060d-4752-9a31-504714eb43ae', embedding=None, metadata={'file_path': '/Users/maysrp/rag/data/test.txt', 'file_name': 'test.txt', 'file_type': 'text/plain', 'file_size': 25, 'creation_date': '2025-12-27', 'last_modified_date': '2025-10-08'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='i am a look!\nThanks alot\n', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}')]
[TextNode(id_='98437de2-9ad7-451d-aa2f-c72c778866f7', embedding=None, metadata={'file_name': 'Suzhou.docx', 'file_path': '/Users/maysrp/rag/data/Suzhou.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10159, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='de9ebe13-a86b-4331-a6aa-8046de5263d1', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'file_name': 'Suzhou.docx', 'file_path': '/Users/maysrp/rag/data/Suzhou.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10159, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, hash='22704cae161d866fe704741b55317fb4f2baf40fd456bfee0c030bd4a9f37e81')}, metadata_template='{key}: {value}', metadata_separator='\n', text='Suzhou is Link’s best city in her live.', mimetype='text/plain', start_char_idx=0, end_char_idx=39, metadata_seperator='\n', text_template='{metadata_str}\n\n{content}'), TextNode(id_='aebe5d8c-e8e0-4e91-8641-2287c045a062', embedding=None, metadata={'file_name': 'game.docx', 'file_path': '/Users/maysrp/rag/data/game.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10138, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='92e769b9-e293-48e2-a5ac-743a753b167a', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'file_name': 'game.docx', 'file_path': '/Users/maysrp/rag/data/game.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10138, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, hash='a4ef473a6499b1e9a6d082cc6e859661785a05b99aeaf00c34acfb969565e11f')}, metadata_template='{key}: {value}', metadata_separator='\n', text='Link love play Switch game!', mimetype='text/plain', start_char_idx=0, end_char_idx=27, metadata_seperator='\n', text_template='{metadata_str}\n\n{content}'), TextNode(id_='dcf48ae6-1d63-4ccf-b21f-ba12852a59df', embedding=None, metadata={'file_name': 'sutdent.docx', 'file_path': '/Users/maysrp/rag/data/sutdent.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10142, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='7cc63b7a-19fb-4d27-b58d-266101e2c49f', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'file_name': 'sutdent.docx', 'file_path': '/Users/maysrp/rag/data/sutdent.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10142, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, hash='dce4f61a4f5f77866c8f3baa92c20997bad74b8ea4b00b6bdbcdca6b5fd240ce')}, metadata_template='{key}: {value}', metadata_separator='\n', text='Link is high school sutdent!', mimetype='text/plain', start_char_idx=0, end_char_idx=28, metadata_seperator='\n', text_template='{metadata_str}\n\n{content}'), TextNode(id_='affc51cf-137b-4306-a047-be08aa95ac62', embedding=None, metadata={'file_path': '/Users/maysrp/rag/data/test.txt', 'file_name': 'test.txt', 'file_type': 'text/plain', 'file_size': 25, 'creation_date': '2025-12-27', 'last_modified_date': '2025-10-08'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='9d3ee148-060d-4752-9a31-504714eb43ae', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'file_path': '/Users/maysrp/rag/data/test.txt', 'file_name': 'test.txt', 'file_type': 'text/plain', 'file_size': 25, 'creation_date': '2025-12-27', 'last_modified_date': '2025-10-08'}, hash='34192438b5e50e0927a1f41c8e40814c5c6e2078c7ab4ec91c732c9938944f50')}, metadata_template='{key}: {value}', metadata_separator='\n', text='i am a look!\nThanks alot', mimetype='text/plain', start_char_idx=0, end_char_idx=24, metadata_seperator='\n', text_template='{metadata_str}\n\n{content}')]
[Document(id_='4221065b-b64d-4c8b-8807-94be61940f8e', embedding=None, metadata={'file_name': 'add.docx', 'file_path': 'add.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10121, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='Link like  NIkon camera .he has a camre that is name is z8', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}')]
[Document(id_='4221065b-b64d-4c8b-8807-94be61940f8e', embedding=None, metadata={'file_name': 'add.docx', 'file_path': 'add.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10121, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03', 'MAC': 'adgfa-192ga', 'document_id': '4221065b-b64d-4c8b-8807-94be61940f8e'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={}, metadata_template='{key}: {value}', metadata_separator='\n', text_resource=MediaResource(embeddings=None, data=None, text='Link like  NIkon camera .he has a camre that is name is z8', path=None, url=None, mimetype=None), image_resource=None, audio_resource=None, video_resource=None, text_template='{metadata_str}\n\n{content}')]
[TextNode(id_='e225ff5c-48db-4e3e-a741-90194180af44', embedding=None, metadata={'file_name': 'add.docx', 'file_path': 'add.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10121, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03', 'MAC': 'adgfa-192ga', 'document_id': '4221065b-b64d-4c8b-8807-94be61940f8e'}, excluded_embed_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], excluded_llm_metadata_keys=['file_name', 'file_type', 'file_size', 'creation_date', 'last_modified_date', 'last_accessed_date'], relationships={<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='4221065b-b64d-4c8b-8807-94be61940f8e', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'file_name': 'add.docx', 'file_path': 'add.docx', 'file_type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'file_size': 10121, 'creation_date': '2026-01-03', 'last_modified_date': '2026-01-03', 'MAC': 'adgfa-192ga', 'document_id': '4221065b-b64d-4c8b-8807-94be61940f8e'}, hash='d907ec8b73619251ad897fc95f680465711bbec8cda67a3494f0d5e6e0e27686')}, metadata_template='{key}: {value}', metadata_separator='\n', text='Link like  NIkon camera .he has a camre that is name is z8', mimetype='text/plain', start_char_idx=0, end_char_idx=58, metadata_seperator='\n', text_template='{metadata_str}\n\n{content}')]
2026-01-07 22:47:07,035 - DEBUG - Building index from IDs objects
2026-01-07 22:47:07,289 - WARNING - As bm25s.BM25 requires k less than or equal to number of nodes added. Overriding the value of similarity_top_k to number of nodes added.
0.267697811126709 <__main__.ChineseBM25Retriever object at 0x14b823620>
Finding newlines for mmindex: 100%|████████| 2.11k/2.11k [00:00<00:00, 19.1MB/s]
Node ID: e225ff5c-48db-4e3e-a741-90194180af44
Text: Link like  NIkon camera .he has a camre that is name is z8
Score:  0.115

Reload BM25 from disk
Node ID: e225ff5c-48db-4e3e-a741-90194180af44
Text: Link like  NIkon camera .he has a camre that is name is z8
Score:  0.115

发表在 None | 留下评论

thinkphp 子查询 闭包

1.最简单 在查询中使用


UserModel::where(‘id’,’in’,function($query){

$query->name(‘book’)->where(‘date’,’=’,’2025-01-07′)->field(‘user_id’);

})->select()

最简单的子查询 分为 2部分 首先 主查询是查询用户的信息,其信息需要由闭包子查询book表中日起为2025-01-07的用户user_id 注意field后面不需要select,且子查询 目标是用一次SQL 语句去查询 不是分步查询!

2.分布标准实现 buildSql

$bsql=BookModel::where(‘date’,’=’,’2025-01-07′)->field(‘user_id’)->buildSql();


UserModel::where(‘id’,’in’,$bsql)->select();

上面使用buildSql()方法来构造语句,然后加入即可。

3.has实现,在模型中可以用has来直接调用关联的模型(tips:with 可以多级关联 A.B B.C 可以实现A.B.C取值)

模型UserModel中

public function book(){

return $this->hasMany(BookModel::Class,’user_id’,’id’);

}

然后使用:

UserModel::has(‘book’,function($query){

$query->where(‘date’,’=’,’2025-01-07′)

})->select();

发表在 None | 留下评论

Thinkphp中模型关联骆峰法

在model里面关联

    public function startTopics(){
        //只对应实际开会的议题
        return $this->hasMany(TopicsModel::class,'start_meeting_id','id')->where('del_time',0);
        
    }
    public function topics(){
        //只对应实际开会的议题
        return $this->hasMany(TopicsModel::class,'meeting_id','id')->where('del_time',0);
    }
    

上面真实情况下 public function startTopics (){}是可以显示 前端模板中也可以直接调用
但是public function strat_topics(){}来关联是不可以的不能有 下划线!必须驼峰法显示,坑了我一天!!!

发表在 None | 留下评论

Thinkphp中 前段使用collection

在之前控制器向前段传值的时候($this->assign()),一直讲模型取得的数据集通过toArray方法转为数组,结果丢失了最好用的方法,向前段传collection数据对象可以使用model中的方法。
如下:
Model A 一对多 关联 Model B
模型A 的关联 b ,这个可以在前段直接取到b

public function b(){

return $this->hasMany(B::Class,’a_id’,’id’);

}

$ac=A::select();

前段传入$ac
<volist name=”ac” id=”vo”>

此处已经加载到内存,不会多加SQL查询

<p>{:count($vo->b->where(‘date’,’2025-01-21′))}</p>

<p>{:$vo->b->where(‘date’,’2025-01-21′)->count()}</p> collection自带到统计方法

下面的回影响性能,多查询
<p>{:$vo->b()->where(‘date’, ‘2025-01-21’)->count()}</p>

</volist>

Collection 数据对象

一、基础统计 / 判断方法(最常用)

方法作用示例(基于$vo->b这个 Collection)
count()统计集合元素数量(替代 PHP 原生count()$vo->b->count() // 统计所有 B 数据
isEmpty()判断集合是否为空$vo->b->isEmpty() // 返回 true/false
isNotEmpty()判断集合是否非空(反向isEmpty()$vo->b->isNotEmpty()
max('字段名')获取指定字段的最大值$vo->b->max('price') // 取 B 表 price 最大值
min('字段名')获取指定字段的最小值$vo->b->min('price')
sum('字段名')计算指定字段的总和$vo->b->sum('amount') // 统计 B 表 amount 字段总和
avg('字段名')计算指定字段的平均值$vo->b->avg('score')

二、筛选 / 查找方法(模板中筛选数据常用)

方法作用示例
where('字段名', '值')筛选符合条件的元素(支持多条件)$vo->b->where('date', '2025-01-21') // 筛选 date 等于指定值的 B 数据
where('字段名', '操作符', '值')带操作符的筛选(>、<、like 等)$vo->b->where('price', '>', 100) // 价格大于 100 的 B 数据
whereLike('字段名', '模糊值')模糊筛选(替代 SQL 的 LIKE)$vo->b->whereLike('name', '%手机%')
whereIn('字段名', [值1, 值2])筛选字段值在指定数组中的元素$vo->b->whereIn('status', [1,2])
whereNotIn('字段名', [值1, 值2])筛选字段值不在指定数组中的元素$vo->b->whereNotIn('id', [5,6])
find('主键值')根据主键查找单个元素$vo->b->find(3) // 查找 B 表 id=3 的记录
first()获取集合中第一个元素$vo->b->where('status', 1)->first() // 取第一个状态为 1 的 B 数据
last()获取集合中最后一个元素$vo->b->last()

三、排序 / 去重方法

方法作用示例
order('字段名', '排序方式')对集合排序(asc/desc)$vo->b->order('create_time', 'desc') // 按创建时间降序
sortBy('字段名')按字段升序排序(简化版order$vo->b->sortBy('price')
sortByDesc('字段名')按字段降序排序$vo->b->sortByDesc('price')
unique('字段名')根据指定字段去重$vo->b->unique('category_id') // 按分类 ID 去重

四、数据提取 / 转换方法

方法作用示例
toArray()转为普通数组(你之前用过的方法)$vo->b->toArray() // 保留字段值,丢失模型方法
all()返回集合底层的数组(等价于toArray()但更语义化)$vo->b->all()
pluck('字段名')提取指定字段的值,返回新集合$vo->b->pluck('name') // 提取所有 B 数据的 name 字段
pluck('字段名', '主键名')提取字段并以主键为键名$vo->b->pluck('name', 'id') // 得到 [id=>name] 的集合
column('字段名')等同于pluck(),兼容 PHP 原生array_column$vo->b->column('price')

五、遍历 / 修改方法(控制器中处理数据常用)

方法作用示例
each(function($item) {})遍历集合,可修改元素$vo->b->each(function($b) { $b->price = $b->price * 0.8; }) // 所有 B 数据价格打 8 折
map(function($item) {})遍历集合,返回新集合$vo->b->map(function($b) { return $b->name; }) // 返回仅包含 name 的新集合

实战示例(模板中组合使用)

<volist name="ac" id="vo">
    <!-- 1. 统计2025-01-21且价格>100的B数据数量 -->
    <p>{:$vo->b->where('date', '2025-01-21')->where('price', '>', 100)->count()}</p>
    
    <!-- 2. 获取符合条件的第一个B数据的名称 -->
    <p>{:$vo->b->where('status', 1)->first()->name ?? '无数据'}</p>
    
    <!-- 3. 计算符合条件的B数据金额总和 -->
    <p>{:$vo->b->where('date', '2025-01-21')->sum('amount')}</p>
    
    <!-- 4. 提取所有B数据的ID,转为逗号分隔的字符串 -->
    <p>{:$vo->b->pluck('id')->implode(',')}</p>
</volist>
发表在 None | 留下评论